Merge branch 'master-jdk17' of https://gitee.com/zhijiantianya/ruoyi-vue-pro into feature/iot

This commit is contained in:
YunaiV 2025-09-03 22:42:43 +08:00
commit 67a44fd334
178 changed files with 3267 additions and 1061 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -308,26 +308,26 @@
| 框架 | 说明 | 版本 | 学习指南 |
|---------------------------------------------------------------------------------------------|------------------|----------------|----------------------------------------------------------------|
| [Spring Boot](https://spring.io/projects/spring-boot) | 应用开发框架 | 3.4.5 | [文档](https://github.com/YunaiV/SpringBoot-Labs) |
| [Spring Boot](https://spring.io/projects/spring-boot) | 应用开发框架 | 3.5.5 | [文档](https://github.com/YunaiV/SpringBoot-Labs) |
| [MySQL](https://www.mysql.com/cn/) | 数据库服务器 | 5.7 / 8.0+ | |
| [Druid](https://github.com/alibaba/druid) | JDBC 连接池、监控组件 | 1.2.23 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
| [MyBatis Plus](https://mp.baomidou.com/) | MyBatis 增强工具包 | 3.5.7 | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) |
| [Druid](https://github.com/alibaba/druid) | JDBC 连接池、监控组件 | 1.2.27 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
| [MyBatis Plus](https://mp.baomidou.com/) | MyBatis 增强工具包 | 3.5.12 | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) |
| [Dynamic Datasource](https://dynamic-datasource.com/) | 动态数据源 | 4.3.1 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
| [Redis](https://redis.io/) | key-value 数据库 | 5.0 / 6.0 /7.0 | |
| [Redisson](https://github.com/redisson/redisson) | Redis 客户端 | 3.32.0 | [文档](http://www.iocoder.cn/Spring-Boot/Redis/?yudao) |
| [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架 | 6.1.10 | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao) |
| [Spring Security](https://github.com/spring-projects/spring-security) | Spring 安全框架 | 6.3.1 | [文档](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) |
| [Hibernate Validator](https://github.com/hibernate/hibernate-validator) | 参数校验组件 | 8.0.1 | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao) |
| [Redisson](https://github.com/redisson/redisson) | Redis 客户端 | 3.35.0 | [文档](http://www.iocoder.cn/Spring-Boot/Redis/?yudao) |
| [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架 | 6.2.9 | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao) |
| [Spring Security](https://github.com/spring-projects/spring-security) | Spring 安全框架 | 6.5.2 | [文档](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) |
| [Hibernate Validator](https://github.com/hibernate/hibernate-validator) | 参数校验组件 | 8.0.2 | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao) |
| [Flowable](https://github.com/flowable/flowable-engine) | 工作流引擎 | 7.0.0 | [文档](https://doc.iocoder.cn/bpm/) |
| [Quartz](https://github.com/quartz-scheduler) | 任务调度组件 | 2.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao) |
| [Springdoc](https://springdoc.org/) | Swagger 文档 | 2.3.0 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) |
| [SkyWalking](https://skywalking.apache.org/) | 分布式应用追踪系统 | 9.0.0 | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao) |
| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin) | Spring Boot 监控平台 | 3.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) |
| [Jackson](https://github.com/FasterXML/jackson) | JSON 工具库 | 2.17.1 | |
| [Quartz](https://github.com/quartz-scheduler) | 任务调度组件 | 2.5.0 | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao) |
| [Springdoc](https://springdoc.org/) | Swagger 文档 | 2.8.9 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) |
| [SkyWalking](https://skywalking.apache.org/) | 分布式应用追踪系统 | 9.5.0 | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao) |
| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin) | Spring Boot 监控平台 | 3.5.2 | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) |
| [Jackson](https://github.com/FasterXML/jackson) | JSON 工具库 | 2.30.14 | |
| [MapStruct](https://mapstruct.org/) | Java Bean 转换 | 1.6.3 | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao) |
| [Lombok](https://projectlombok.org/) | 消除冗长的 Java 代码 | 1.18.34 | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao) |
| [JUnit](https://junit.org/junit5/) | Java 单元测试框架 | 5.10.1 | - |
| [Mockito](https://github.com/mockito/mockito) | Java Mock 框架 | 5.7.0 | - |
| [Lombok](https://projectlombok.org/) | 消除冗长的 Java 代码 | 1.18.38 | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao) |
| [JUnit](https://junit.org/junit5/) | Java 单元测试框架 | 5.12.2 | - |
| [Mockito](https://github.com/mockito/mockito) | Java Mock 框架 | 5.17.0 | - |
## 🐷 演示图

10
pom.xml
View File

@ -24,7 +24,7 @@
<!-- <module>yudao-module-crm</module>-->
<!-- <module>yudao-module-erp</module>-->
<!-- <module>yudao-module-ai</module>-->
<module>yudao-module-iot</module>
<!-- <module>yudao-module-iot</module>-->
</modules>
<name>${project.artifactId}</name>
@ -32,17 +32,17 @@
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
<properties>
<revision>2025.08-SNAPSHOT</revision>
<revision>2025.09-SNAPSHOT</revision>
<!-- Maven 相关 -->
<java.version>17</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<maven-surefire-plugin.version>3.2.2</maven-surefire-plugin.version>
<maven-surefire-plugin.version>3.5.3</maven-surefire-plugin.version>
<maven-compiler-plugin.version>3.14.0</maven-compiler-plugin.version>
<flatten-maven-plugin.version>1.6.0</flatten-maven-plugin.version>
<flatten-maven-plugin.version>1.7.2</flatten-maven-plugin.version>
<!-- maven-surefire-plugin 暂时无法通过 bom 的依赖读取(兼容老版本 IDEA 2024 及以前版本) -->
<lombok.version>1.18.38</lombok.version>
<spring.boot.version>3.4.5</spring.boot.version>
<spring.boot.version>3.5.5</spring.boot.version>
<mapstruct.version>1.6.3</mapstruct.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

View File

@ -4303,7 +4303,7 @@ CREATE TABLE system_tenant
contact_name varchar(30) NOT NULL,
contact_mobile varchar(500) DEFAULT NULL NULL,
status smallint DEFAULT 0 NOT NULL,
website varchar(256) DEFAULT '' NULL,
websites varchar(256) DEFAULT '' NULL,
package_id bigint NOT NULL,
expire_time datetime NOT NULL,
account_count int NOT NULL,
@ -4320,7 +4320,7 @@ COMMENT ON COLUMN system_tenant.contact_user_id IS '联系人的用户编号';
COMMENT ON COLUMN system_tenant.contact_name IS '联系人';
COMMENT ON COLUMN system_tenant.contact_mobile IS '联系手机';
COMMENT ON COLUMN system_tenant.status IS '租户状态0正常 1停用';
COMMENT ON COLUMN system_tenant.website IS '绑定域名';
COMMENT ON COLUMN system_tenant.websites IS '绑定域名数组';
COMMENT ON COLUMN system_tenant.package_id IS '租户套餐编号';
COMMENT ON COLUMN system_tenant.expire_time IS '过期时间';
COMMENT ON COLUMN system_tenant.account_count IS '账号数量';
@ -4336,9 +4336,9 @@ COMMENT ON TABLE system_tenant IS '租户表';
-- ----------------------------
-- @formatter:off
SET IDENTITY_INSERT system_tenant ON;
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (1, '芋道源码', NULL, '芋艿', '17321315478', 0, 'www.iocoder.cn', 0, '2099-02-19 17:14:16', 9999, '1', '2021-01-05 17:03:47', '1', '2023-11-06 11:41:41', '0');
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (121, '小租户', 110, '小王2', '15601691300', 0, 'zsxq.iocoder.cn', 111, '2026-07-10 00:00:00', 30, '1', '2022-02-22 00:56:14', '1', '2025-04-03 21:33:01', '0');
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (122, '测试租户', 113, '芋道', '15601691300', 0, 'test.iocoder.cn', 111, '2022-04-29 00:00:00', 50, '1', '2022-03-07 21:37:58', '1', '2024-09-22 12:10:50', '0');
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, websites, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (1, '芋道源码', NULL, '芋艿', '17321315478', 0, 'www.iocoder.cn', 0, '2099-02-19 17:14:16', 9999, '1', '2021-01-05 17:03:47', '1', '2023-11-06 11:41:41', '0');
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, websites, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (121, '小租户', 110, '小王2', '15601691300', 0, 'zsxq.iocoder.cn', 111, '2026-07-10 00:00:00', 30, '1', '2022-02-22 00:56:14', '1', '2025-04-03 21:33:01', '0');
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, websites, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (122, '测试租户', 113, '芋道', '15601691300', 0, 'test.iocoder.cn', 111, '2022-04-29 00:00:00', 50, '1', '2022-03-07 21:37:58', '1', '2024-09-22 12:10:50', '0');
COMMIT;
SET IDENTITY_INSERT system_tenant OFF;
-- @formatter:on

View File

@ -4608,7 +4608,7 @@ CREATE TABLE system_tenant
contact_name varchar(30) NOT NULL,
contact_mobile varchar(500) NULL DEFAULT NULL,
status int2 NOT NULL DEFAULT 0,
website varchar(256) NULL DEFAULT '',
websites varchar(256) NULL DEFAULT '',
package_id int8 NOT NULL,
expire_time timestamp NOT NULL,
account_count int4 NOT NULL,
@ -4628,7 +4628,7 @@ COMMENT ON COLUMN system_tenant.contact_user_id IS '联系人的用户编号';
COMMENT ON COLUMN system_tenant.contact_name IS '联系人';
COMMENT ON COLUMN system_tenant.contact_mobile IS '联系手机';
COMMENT ON COLUMN system_tenant.status IS '租户状态0正常 1停用';
COMMENT ON COLUMN system_tenant.website IS '绑定域名';
COMMENT ON COLUMN system_tenant.websites IS '绑定域名数组';
COMMENT ON COLUMN system_tenant.package_id IS '租户套餐编号';
COMMENT ON COLUMN system_tenant.expire_time IS '过期时间';
COMMENT ON COLUMN system_tenant.account_count IS '账号数量';
@ -4644,9 +4644,9 @@ COMMENT ON TABLE system_tenant IS '租户表';
-- ----------------------------
-- @formatter:off
BEGIN;
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (1, '芋道源码', NULL, '芋艿', '17321315478', 0, 'www.iocoder.cn', 0, '2099-02-19 17:14:16', 9999, '1', '2021-01-05 17:03:47', '1', '2023-11-06 11:41:41', '0');
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (121, '小租户', 110, '小王2', '15601691300', 0, 'zsxq.iocoder.cn', 111, '2026-07-10 00:00:00', 30, '1', '2022-02-22 00:56:14', '1', '2025-04-03 21:33:01', '0');
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (122, '测试租户', 113, '芋道', '15601691300', 0, 'test.iocoder.cn', 111, '2022-04-29 00:00:00', 50, '1', '2022-03-07 21:37:58', '1', '2024-09-22 12:10:50', '0');
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, websites, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (1, '芋道源码', NULL, '芋艿', '17321315478', 0, 'www.iocoder.cn', 0, '2099-02-19 17:14:16', 9999, '1', '2021-01-05 17:03:47', '1', '2023-11-06 11:41:41', '0');
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, websites, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (121, '小租户', 110, '小王2', '15601691300', 0, 'zsxq.iocoder.cn', 111, '2026-07-10 00:00:00', 30, '1', '2022-02-22 00:56:14', '1', '2025-04-03 21:33:01', '0');
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, websites, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (122, '测试租户', 113, '芋道', '15601691300', 0, 'test.iocoder.cn', 111, '2022-04-29 00:00:00', 50, '1', '2022-03-07 21:37:58', '1', '2024-09-22 12:10:50', '0');
COMMIT;
-- @formatter:on

View File

@ -11,7 +11,7 @@
Target Server Version : 80200 (8.2.0)
File Encoding : 65001
Date: 12/05/2025 09:09:45
Date: 31/08/2025 11:12:28
*/
SET NAMES utf8mb4;
@ -49,7 +49,7 @@ CREATE TABLE `infra_api_access_log` (
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_create_time`(`create_time` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 35953 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'API 访问日志表';
) ENGINE = InnoDB AUTO_INCREMENT = 36233 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'API 访问日志表';
-- ----------------------------
-- Records of infra_api_access_log
@ -91,7 +91,7 @@ CREATE TABLE `infra_api_error_log` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 22175 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志';
) ENGINE = InnoDB AUTO_INCREMENT = 22656 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志';
-- ----------------------------
-- Records of infra_api_error_log
@ -128,7 +128,7 @@ CREATE TABLE `infra_codegen_column` (
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2538 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表字段定义';
) ENGINE = InnoDB AUTO_INCREMENT = 2603 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表字段定义';
-- ----------------------------
-- Records of infra_codegen_column
@ -166,7 +166,7 @@ CREATE TABLE `infra_codegen_table` (
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 191 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表定义';
) ENGINE = InnoDB AUTO_INCREMENT = 196 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表定义';
-- ----------------------------
-- Records of infra_codegen_table
@ -251,7 +251,7 @@ CREATE TABLE `infra_file` (
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1898 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表';
) ENGINE = InnoDB AUTO_INCREMENT = 1983 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表';
-- ----------------------------
-- Records of infra_file
@ -276,21 +276,22 @@ CREATE TABLE `infra_file_config` (
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 31 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件配置表';
) ENGINE = InnoDB AUTO_INCREMENT = 35 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件配置表';
-- ----------------------------
-- Records of infra_file_config
-- ----------------------------
BEGIN;
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4, '数据库(示例)', 1, '我是数据库', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.db.DBFileClientConfig\",\"domain\":\"http://127.0.0.1:48080\"}', '1', '2022-03-15 23:56:24', '1', '2025-05-02 18:30:28', b'0');
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (22, '七牛存储器(示例)', 20, '请换成你自己的密钥!!!', b'1', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"s3.cn-south-1.qiniucs.com\",\"domain\":\"http://test.yudao.iocoder.cn\",\"bucket\":\"ruoyi-vue-pro\",\"accessKey\":\"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS\",\"accessSecret\":\"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY\",\"enablePathStyleAccess\":false}', '1', '2024-01-13 22:11:12', '1', '2025-05-02 18:30:28', b'0');
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (24, '腾讯云存储(示例)', 20, '请换成你的密钥!!!', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"https://cos.ap-shanghai.myqcloud.com\",\"domain\":\"http://tengxun-oss.iocoder.cn\",\"bucket\":\"aoteman-1255880240\",\"accessKey\":\"AKIDAF6WSh1uiIjwqtrOsGSN3WryqTM6cTMt\",\"accessSecret\":\"X\"}', '1', '2024-11-09 16:03:22', '1', '2025-05-02 18:30:28', b'0');
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (25, '阿里云存储(示例)', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"oss-cn-beijing.aliyuncs.com\",\"domain\":\"http://ali-oss.iocoder.cn\",\"bucket\":\"yunai-aoteman\",\"accessKey\":\"LTAI5tEQLgnDyjh3WpNcdMKA\",\"accessSecret\":\"X\",\"enablePathStyleAccess\":false}', '1', '2024-11-09 16:47:08', '1', '2025-05-02 18:30:28', b'0');
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (26, '火山云存储(示例)', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"tos-s3-cn-beijing.volces.com\",\"domain\":null,\"bucket\":\"yunai\",\"accessKey\":\"AKLTZjc3Zjc4MzZmMjU3NDk0ZTgxYmIyMmFkNTIwMDI1ZGE\",\"accessSecret\":\"X==\",\"enablePathStyleAccess\":false}', '1', '2024-11-09 16:56:42', '1', '2025-05-02 18:30:28', b'0');
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (27, '华为云存储(示例)', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"obs.cn-east-3.myhuaweicloud.com\",\"domain\":\"\",\"bucket\":\"yudao\",\"accessKey\":\"PVDONDEIOTW88LF8DC4U\",\"accessSecret\":\"X\",\"enablePathStyleAccess\":false}', '1', '2024-11-09 17:18:41', '1', '2025-05-02 18:30:28', b'0');
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (28, 'MinIO 存储(示例)', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"http://127.0.0.1:9000\",\"domain\":\"http://127.0.0.1:9000/yudao\",\"bucket\":\"yudao\",\"accessKey\":\"admin\",\"accessSecret\":\"password\",\"enablePathStyleAccess\":false}', '1', '2024-11-09 17:43:10', '1', '2025-05-02 18:30:28', b'0');
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (29, '本地存储(示例)', 10, '仅适合 mac 或 windows', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.local.LocalFileClientConfig\",\"basePath\":\"/Users/yunai/tmp/file\",\"domain\":\"http://127.0.0.1:48080\"}', '1', '2025-05-02 11:25:45', '1', '2025-05-02 18:30:28', b'0');
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (30, 'SFTP 存储(示例)', 12, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.sftp.SftpFileClientConfig\",\"basePath\":\"/upload\",\"domain\":\"http://127.0.0.1:48080\",\"host\":\"127.0.0.1\",\"port\":2222,\"username\":\"foo\",\"password\":\"pass\"}', '1', '2025-05-02 16:34:10', '1', '2025-05-02 18:30:28', b'0');
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4, '数据库(示例)', 1, '我是数据库', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.db.DBFileClientConfig\",\"domain\":\"http://127.0.0.1:48080\"}', '1', '2022-03-15 23:56:24', '1', '2025-08-18 08:35:14', b'0');
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (22, '七牛存储器(示例)', 20, '请换成你自己的密钥!!!', b'1', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"s3.cn-south-1.qiniucs.com\",\"domain\":\"http://test.yudao.iocoder.cn\",\"bucket\":\"ruoyi-vue-pro\",\"accessKey\":\"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS\",\"accessSecret\":\"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":true}', '1', '2024-01-13 22:11:12', '1', '2025-08-18 08:35:14', b'0');
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (24, '腾讯云存储(示例)', 20, '请换成你的密钥!!!', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"https://cos.ap-shanghai.myqcloud.com\",\"domain\":\"http://tengxun-oss.iocoder.cn\",\"bucket\":\"aoteman-1255880240\",\"accessKey\":\"AKIDAF6WSh1uiIjwqtrOsGSN3WryqTM6cTMt\",\"accessSecret\":\"X\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":true}', '1', '2024-11-09 16:03:22', '1', '2025-08-18 08:35:14', b'0');
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (25, '阿里云存储(示例)', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"oss-cn-beijing.aliyuncs.com\",\"domain\":\"http://ali-oss.iocoder.cn\",\"bucket\":\"yunai-aoteman\",\"accessKey\":\"LTAI5tEQLgnDyjh3WpNcdMKA\",\"accessSecret\":\"X\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":true}', '1', '2024-11-09 16:47:08', '1', '2025-08-18 08:35:14', b'0');
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (26, '火山云存储(示例)', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"tos-s3-cn-beijing.volces.com\",\"domain\":null,\"bucket\":\"yunai\",\"accessKey\":\"AKLTZjc3Zjc4MzZmMjU3NDk0ZTgxYmIyMmFkNTIwMDI1ZGE\",\"accessSecret\":\"X==\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":true}', '1', '2024-11-09 16:56:42', '1', '2025-08-18 08:35:14', b'0');
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (27, '华为云存储(示例)', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"obs.cn-east-3.myhuaweicloud.com\",\"domain\":\"\",\"bucket\":\"yudao\",\"accessKey\":\"PVDONDEIOTW88LF8DC4U\",\"accessSecret\":\"X\",\"enablePathStyleAccess\":false}', '1', '2024-11-09 17:18:41', '1', '2025-08-18 08:35:14', b'0');
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (28, 'MinIO 存储(示例)', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"http://127.0.0.1:9000\",\"domain\":\"http://127.0.0.1:9000/yudao\",\"bucket\":\"yudao\",\"accessKey\":\"admin\",\"accessSecret\":\"password\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":true}', '1', '2024-11-09 17:43:10', '1', '2025-08-18 08:35:14', b'0');
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (29, '本地存储(示例)', 10, '仅适合 mac 或 windows', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.local.LocalFileClientConfig\",\"basePath\":\"/Users/yunai/tmp/file\",\"domain\":\"http://127.0.0.1:48080\"}', '1', '2025-05-02 11:25:45', '1', '2025-08-18 08:35:14', b'0');
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (30, 'SFTP 存储(示例)', 12, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.sftp.SftpFileClientConfig\",\"basePath\":\"/upload\",\"domain\":\"http://127.0.0.1:48080\",\"host\":\"127.0.0.1\",\"port\":2222,\"username\":\"foo\",\"password\":\"pass\"}', '1', '2025-05-02 16:34:10', '1', '2025-08-18 08:35:14', b'0');
INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (34, '七牛云存储【私有】(示例)', 20, '请换成你自己的密钥!!!', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"s3.cn-south-1.qiniucs.com\",\"domain\":\"http://t151glocd.hn-bkt.clouddn.com\",\"bucket\":\"ruoyi-vue-pro-private\",\"accessKey\":\"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS\",\"accessSecret\":\"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":false}', '1', '2025-08-17 21:22:00', '1', '2025-08-18 08:35:55', b'0');
COMMIT;
-- ----------------------------
@ -336,7 +337,7 @@ CREATE TABLE `infra_job` (
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 36 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务表';
) ENGINE = InnoDB AUTO_INCREMENT = 38 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务表';
-- ----------------------------
-- Records of infra_job
@ -355,6 +356,8 @@ INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`
INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (27, '任务日志清理 Job', 2, 'jobLogCleanJob', '', '0 0 0 * * ?', 3, 0, 0, '1', '2023-10-03 11:01:33', '1', '2024-09-12 13:40:34', b'0');
INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (33, 'demoJob', 2, 'demoJob', '', '0 * * * * ?', 1, 1, 0, '1', '2024-10-27 19:38:46', '1', '2025-05-10 18:13:54', b'0');
INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (35, '转账订单的同步 Job', 2, 'payTransferSyncJob', '', '0 * * * * ?', 0, 0, 0, '1', '2025-05-10 17:35:54', '1', '2025-05-10 18:13:52', b'0');
INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (36, 'IoT 设备离线检查 Job', 2, 'iotDeviceOfflineCheckJob', '', '0 * * * * ?', 0, 0, 0, '1', '2025-07-03 23:48:44', '\"1\"', '2025-07-03 23:48:47', b'0');
INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (37, 'IoT OTA 升级推送 Job', 2, 'iotOtaUpgradeJob', '', '0 * * * * ?', 0, 0, 0, '1', '2025-07-03 23:49:07', '\"1\"', '2025-07-03 23:49:13', b'0');
COMMIT;
-- ----------------------------
@ -378,7 +381,7 @@ CREATE TABLE `infra_job_log` (
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 972 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务日志表';
) ENGINE = InnoDB AUTO_INCREMENT = 980 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务日志表';
-- ----------------------------
-- Records of infra_job_log
@ -448,7 +451,7 @@ CREATE TABLE `system_dict_data` (
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3003 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典数据表';
) ENGINE = InnoDB AUTO_INCREMENT = 3031 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典数据表';
-- ----------------------------
-- Records of system_dict_data
@ -639,7 +642,7 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1230, 13, '支付宝条码支付', 'alipay_bar', 'pay_channel_code', 0, 'primary', '', '支付宝条码支付', '1', '2023-02-18 23:32:24', '1', '2023-07-19 20:09:23', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1231, 10, 'Vue2 Element UI 标准模版', '10', 'infra_codegen_front_type', 0, '', '', '', '1', '2023-04-13 00:03:55', '1', '2023-04-13 00:03:55', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1232, 20, 'Vue3 Element Plus 标准模版', '20', 'infra_codegen_front_type', 0, '', '', '', '1', '2023-04-13 00:04:08', '1', '2023-04-13 00:04:08', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1234, 30, 'Vben2.0 Ant Design Schema 模版', '30', 'infra_codegen_front_type', 0, '', '', '', '1', '2023-04-13 00:04:26', '1', '2025-04-23 21:27:34', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1234, 30, 'Vben2.0 Ant Design Schema 模版', '30', 'infra_codegen_front_type', 1, '', '', '', '1', '2023-04-13 00:04:26', '1', '2025-07-27 10:55:14', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1244, 0, '按件', '1', 'trade_delivery_express_charge_mode', 0, '', '', '', '1', '2023-05-21 22:46:40', '1', '2023-05-21 22:46:40', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1245, 1, '按重量', '2', 'trade_delivery_express_charge_mode', 0, '', '', '', '1', '2023-05-21 22:46:58', '1', '2023-05-21 22:46:58', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1246, 2, '按体积', '3', 'trade_delivery_express_charge_mode', 0, '', '', '', '1', '2023-05-21 22:47:18', '1', '2023-05-21 22:47:18', b'0');
@ -881,36 +884,21 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1691, 6, '重排', '6', 'ai_model_type', 0, '', '', '', '1', '2025-03-03 12:28:26', '1', '2025-03-03 12:28:26', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1692, 14, 'MiniMax', 'MiniMax', 'ai_platform', 0, '', '', '', '1', '2025-03-11 20:04:51', '1', '2025-03-11 20:04:51', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1693, 15, '月之暗灭', 'Moonshot', 'ai_platform', 0, '', '', '', '1', '2025-03-11 20:05:08', '1', '2025-03-11 20:05:08', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2000, 0, '标准数据格式JSON', '0', 'iot_data_format', 0, 'default', '', '', '1', '2024-08-10 11:53:26', '1', '2025-03-17 09:28:16', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2001, 1, '透传/自定义', '1', 'iot_data_format', 0, 'default', '', '', '1', '2024-08-10 11:53:37', '1', '2025-03-17 09:28:19', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2002, 0, '直连设备', '0', 'iot_product_device_type', 0, 'default', '', '', '1', '2024-08-10 11:54:58', '1', '2025-03-17 09:28:22', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2003, 2, '网关设备', '2', 'iot_product_device_type', 0, 'default', '', '', '1', '2024-08-10 11:55:08', '1', '2025-03-17 09:28:28', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2004, 1, '网关子设备', '1', 'iot_product_device_type', 0, 'default', '', '', '1', '2024-08-10 11:55:20', '1', '2025-03-17 09:28:31', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2005, 1, '已发布', '1', 'iot_product_status', 0, 'success', '', '', '1', '2024-08-10 12:10:33', '1', '2025-03-17 09:28:34', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2006, 0, '开发中', '0', 'iot_product_status', 0, 'default', '', '', '1', '2024-08-10 14:19:18', '1', '2025-03-17 09:28:39', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2007, 0, '弱校验', '0', 'iot_validate_type', 0, '', '', '', '1', '2024-09-06 20:05:48', '1', '2025-03-17 09:28:41', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2008, 1, '免校验', '1', 'iot_validate_type', 0, '', '', '', '1', '2024-09-06 20:06:03', '1', '2025-03-17 09:28:44', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2009, 0, 'Wi-Fi', '0', 'iot_net_type', 0, '', '', '', '1', '2024-09-06 22:04:47', '1', '2025-03-17 09:28:47', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2010, 1, '蜂窝2G / 3G / 4G / 5G', '1', 'iot_net_type', 0, '', '', '', '1', '2024-09-06 22:05:14', '1', '2025-03-17 09:28:49', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2010, 1, '移动网络', '1', 'iot_net_type', 0, '', '', '', '1', '2024-09-06 22:05:14', '1', '2025-06-12 23:27:19', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2011, 2, '以太网', '2', 'iot_net_type', 0, '', '', '', '1', '2024-09-06 22:05:35', '1', '2025-03-17 09:28:51', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2012, 3, '其他', '3', 'iot_net_type', 0, '', '', '', '1', '2024-09-06 22:05:52', '1', '2025-03-17 09:28:54', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2013, 0, '自定义', '0', 'iot_protocol_type', 0, '', '', '', '1', '2024-09-06 22:26:10', '1', '2025-03-17 09:28:56', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2014, 1, 'Modbus', '1', 'iot_protocol_type', 0, '', '', '', '1', '2024-09-06 22:26:21', '1', '2025-03-17 09:28:58', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2015, 2, 'OPC UA', '2', 'iot_protocol_type', 0, '', '', '', '1', '2024-09-06 22:26:31', '1', '2025-03-17 09:29:00', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2016, 3, 'ZigBee', '3', 'iot_protocol_type', 0, '', '', '', '1', '2024-09-06 22:26:39', '1', '2025-03-17 09:29:04', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2017, 4, 'BLE', '4', 'iot_protocol_type', 0, '', '', '', '1', '2024-09-06 22:26:48', '1', '2025-03-17 09:29:06', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2018, 0, '未激活', '0', 'iot_device_state', 0, '', '', '', '1', '2024-09-21 08:13:34', '1', '2025-03-17 09:29:09', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2019, 1, '在线', '1', 'iot_device_state', 0, '', '', '', '1', '2024-09-21 08:13:48', '1', '2025-03-17 09:29:12', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2020, 2, '离线', '2', 'iot_device_state', 0, '', '', '', '1', '2024-09-21 08:13:59', '1', '2025-03-17 09:29:14', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2021, 1, '属性', '1', 'iot_thing_model_type', 0, '', '', '', '1', '2024-09-29 20:03:01', '1', '2025-03-17 09:29:24', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2022, 2, '服务', '2', 'iot_thing_model_type', 0, '', '', '', '1', '2024-09-29 20:03:11', '1', '2025-03-17 09:29:27', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2023, 3, '事件', '3', 'iot_thing_model_type', 0, '', '', '', '1', '2024-09-29 20:03:20', '1', '2025-03-17 09:29:29', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2024, 1, 'JAR 部署', '0', 'iot_plugin_deploy_type', 0, '', '', '', '1', '2024-12-13 10:55:32', '1', '2025-03-17 09:29:32', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2025, 2, '独立部署', '1', 'iot_plugin_deploy_type', 0, '', '', '', '1', '2024-12-13 10:55:43', '1', '2025-03-17 09:29:34', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2026, 0, '停止', '0', 'iot_plugin_status', 0, 'danger', '', '', '1', '2024-12-13 11:07:37', '1', '2025-03-17 09:29:37', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2027, 1, '运行', '1', 'iot_plugin_status', 0, '', '', '', '1', '2024-12-13 11:07:45', '1', '2025-03-17 09:34:17', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2028, 0, '普通插件', '0', 'iot_plugin_type', 0, '', '', '', '1', '2024-12-13 11:08:32', '1', '2025-03-17 09:34:19', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2029, 1, '设备插件', '1', 'iot_plugin_type', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:34:22', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2030, 1, '升每分钟', 'L/min', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:34:24', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2031, 2, '毫克每千克', 'mg/kg', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:34:27', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2032, 3, '浊度', 'NTU', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:34:31', b'0');
@ -1043,20 +1031,59 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2160, 130, '分米', 'dm', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2161, 131, '千米', 'km', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2162, 132, '', 'm', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2163, 1, '输入', '1', 'iot_data_bridge_direction_enum', 0, 'primary', '', '', '1', '2025-03-09 12:38:24', '1', '2025-03-17 09:40:46', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2164, 2, '输出', '2', 'iot_data_bridge_direction_enum', 0, 'primary', '', '', '1', '2025-03-09 12:38:36', '1', '2025-03-17 09:40:46', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2165, 1, 'HTTP', '1', 'iot_data_bridge_type_enum', 0, 'primary', '', '', '1', '2025-03-09 12:39:54', '1', '2025-03-17 09:40:46', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2166, 2, 'TCP', '2', 'iot_data_bridge_type_enum', 0, 'primary', '', '', '1', '2025-03-09 12:40:06', '1', '2025-03-17 09:40:46', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2167, 3, 'WEBSOCKET', '3', 'iot_data_bridge_type_enum', 0, 'primary', '', '', '1', '2025-03-09 12:40:24', '1', '2025-03-17 09:40:46', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2168, 10, 'MQTT', '10', 'iot_data_bridge_type_enum', 0, 'primary', '', '', '1', '2025-03-09 12:40:37', '1', '2025-03-17 09:40:46', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2169, 20, 'DATABASE', '20', 'iot_data_bridge_type_enum', 0, 'primary', '', '', '1', '2025-03-09 12:41:05', '1', '2025-03-17 09:40:46', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2170, 21, 'REDIS_STREAM', '21', 'iot_data_bridge_type_enum', 0, 'primary', '', '', '1', '2025-03-09 12:41:18', '1', '2025-03-17 09:40:46', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2171, 30, 'ROCKETMQ', '30', 'iot_data_bridge_type_enum', 0, 'primary', '', '', '1', '2025-03-09 12:41:30', '1', '2025-03-17 09:40:46', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2172, 31, 'RABBITMQ', '31', 'iot_data_bridge_type_enum', 0, 'primary', '', '', '1', '2025-03-09 12:41:47', '1', '2025-03-17 09:40:46', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2173, 32, 'KAFKA', '32', 'iot_data_bridge_type_enum', 0, 'primary', '', '', '1', '2025-03-09 12:41:59', '1', '2025-03-17 09:40:46', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2165, 1, 'HTTP', '1', 'iot_data_sink_type_enum', 0, 'default', '', '', '1', '2025-03-09 12:39:54', '1', '2025-06-24 12:44:47', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2166, 2, 'TCP', '2', 'iot_data_sink_type_enum', 0, 'default', '', '', '1', '2025-03-09 12:40:06', '1', '2025-06-24 12:44:46', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2167, 3, 'WebSocket', '3', 'iot_data_sink_type_enum', 0, 'default', '', '', '1', '2025-03-09 12:40:24', '1', '2025-06-24 12:44:45', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2168, 10, 'MQTT', '10', 'iot_data_sink_type_enum', 0, 'default', '', '', '1', '2025-03-09 12:40:37', '1', '2025-06-24 12:44:44', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2169, 20, 'Database', '20', 'iot_data_sink_type_enum', 0, 'default', '', '', '1', '2025-03-09 12:41:05', '1', '2025-06-24 12:44:44', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2170, 21, 'Redis Stream', '21', 'iot_data_sink_type_enum', 0, 'default', '', '', '1', '2025-03-09 12:41:18', '1', '2025-06-24 12:44:43', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2171, 30, 'RocketMQ', '30', 'iot_data_sink_type_enum', 0, 'default', '', '', '1', '2025-03-09 12:41:30', '1', '2025-06-24 12:44:42', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2172, 31, 'RabbitMQ', '31', 'iot_data_sink_type_enum', 0, 'default', '', '', '1', '2025-03-09 12:41:47', '1', '2025-06-24 12:44:41', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2173, 32, 'Kafka', '32', 'iot_data_sink_type_enum', 0, 'default', '', '', '1', '2025-03-09 12:41:59', '1', '2025-06-24 12:44:39', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2174, 1, '设备上下线变更', '1', 'iot_rule_scene_trigger_type_enum', 0, 'primary', '', '', '1', '2025-03-20 15:00:01', '\"1\"', '2025-07-06 10:28:16', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2175, 2, '物模型属性上报', '2', 'iot_rule_scene_trigger_type_enum', 0, 'primary', '', '', '1', '2025-03-20 15:00:09', '\"1\"', '2025-07-06 10:28:22', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2176, 1, '设备状态', 'state', 'iot_device_message_type_enum', 0, 'primary', '', '', '1', '2025-03-20 15:24:58', '1', '2025-03-20 15:24:58', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2177, 2, '设备属性', 'property', 'iot_device_message_type_enum', 0, 'primary', '', '', '1', '2025-03-20 15:25:09', '1', '2025-03-20 15:25:09', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2178, 3, '设备事件', 'event', 'iot_device_message_type_enum', 0, 'primary', '', '', '1', '2025-03-20 15:25:23', '1', '2025-03-20 15:25:23', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2179, 4, '设备服务', 'service', 'iot_device_message_type_enum', 0, 'primary', '', '', '1', '2025-03-20 15:25:39', '1', '2025-03-20 15:25:39', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2180, 5, '设备配置', 'config', 'iot_device_message_type_enum', 0, 'primary', '', '', '1', '2025-03-20 15:25:51', '1', '2025-03-20 15:25:57', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2181, 6, '设备 OTA', 'ota', 'iot_device_message_type_enum', 0, 'primary', '', '', '1', '2025-03-20 15:26:17', '1', '2025-03-20 15:26:17', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2182, 7, '设备注册', 'register', 'iot_device_message_type_enum', 0, 'primary', '', '', '1', '2025-03-20 15:26:35', '1', '2025-03-20 15:26:35', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2183, 8, '设备拓扑', 'topology', 'iot_device_message_type_enum', 0, 'primary', '', '', '1', '2025-03-20 15:26:46', '1', '2025-03-20 15:26:46', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2184, 1, '设备属性设置', '1', 'iot_rule_scene_action_type_enum', 0, 'primary', '', '', '1', '2025-03-28 15:27:12', '\"1\"', '2025-07-06 10:37:33', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2185, 2, '设备服务调用', '2', 'iot_rule_scene_action_type_enum', 0, 'primary', '', '', '1', '2025-03-28 15:27:25', '\"1\"', '2025-07-06 10:37:41', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2186, 100, '告警触发', '100', 'iot_rule_scene_action_type_enum', 0, 'primary', '', '', '1', '2025-03-28 15:27:35', '\"1\"', '2025-07-06 10:37:50', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3000, 16, '百川智能', 'BaiChuan', 'ai_platform', 0, '', '', '', '1', '2025-03-23 12:15:46', '1', '2025-03-23 12:15:46', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3001, 50, 'Vben5.0 Ant Design Schema 模版', '40', 'infra_codegen_front_type', 0, '', '', NULL, '1', '2025-04-23 21:47:47', '1', '2025-05-02 12:01:15', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3002, 6, '支付宝余额', '6', 'brokerage_withdraw_type', 0, '', '', 'API 打款', '1', '2025-05-10 08:24:49', '1', '2025-05-10 08:24:49', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3003, 1, 'Alink', 'Alink', 'iot_codec_type', 0, '', '', '阿里云 Alink', '1', '2025-06-12 22:56:06', '1', '2025-06-12 23:22:24', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3004, 3, 'WARN', '3', 'iot_alert_level', 0, 'warning', '', '', '1', '2025-06-27 20:32:22', '1', '2025-06-27 20:34:31', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3005, 1, 'INFO', '1', 'iot_alert_level', 0, 'primary', '', '', '1', '2025-06-27 20:33:28', '1', '2025-06-27 20:34:35', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3006, 5, 'ERROR', '5', 'iot_alert_level', 0, 'danger', '', '', '1', '2025-06-27 20:33:50', '1', '2025-06-27 20:33:50', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3007, 1, '短信', '1', 'iot_alert_receive_type', 0, '', '', '', '1', '2025-06-27 22:49:30', '1', '2025-06-27 22:49:30', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3008, 2, '邮箱', '2', 'iot_alert_receive_type', 0, '', '', '', '1', '2025-06-27 22:49:39', '1', '2025-06-27 22:50:07', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3009, 3, '站内信', '3', 'iot_alert_receive_type', 0, '', '', '', '1', '2025-06-27 22:50:20', '1', '2025-06-27 22:50:20', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3010, 1, '全部设备', '1', 'iot_ota_task_device_scope', 0, '', '', '', '1', '2025-07-02 09:43:09', '1', '2025-07-02 09:43:09', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3011, 2, '指定设备', '2', 'iot_ota_task_device_scope', 0, '', '', '', '1', '2025-07-02 09:43:15', '1', '2025-07-02 09:43:15', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3012, 10, '进行中', '10', 'iot_ota_task_status', 0, 'primary', '', '', '1', '2025-07-02 09:44:01', '\"1\"', '2025-07-02 09:44:21', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3013, 20, '已结束', '20', 'iot_ota_task_status', 0, 'success', '', '', '1', '2025-07-02 09:44:14', '\"1\"', '2025-07-02 23:56:12', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3014, 30, '已取消', '30', 'iot_ota_task_status', 0, 'danger', '', '', '1', '2025-07-02 09:44:36', '1', '2025-07-02 09:44:36', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3015, 0, '待推送', '0', 'iot_ota_task_record_status', 0, '', '', '', '1', '2025-07-02 09:45:16', '1', '2025-07-02 09:45:16', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3016, 10, '已推送', '10', 'iot_ota_task_record_status', 0, '', '', '', '1', '2025-07-02 09:45:25', '1', '2025-07-02 09:45:25', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3017, 20, '升级中', '20', 'iot_ota_task_record_status', 0, 'primary', '', '', '1', '2025-07-02 09:45:37', '1', '2025-07-02 09:45:37', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3018, 30, '升级成功', '30', 'iot_ota_task_record_status', 0, 'success', '', '', '1', '2025-07-02 09:45:47', '1', '2025-07-02 09:45:47', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3019, 40, '升级失败', '40', 'iot_ota_task_record_status', 0, 'danger', '', '', '1', '2025-07-02 09:46:02', '1', '2025-07-02 09:46:02', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3020, 50, '升级取消', '50', 'iot_ota_task_record_status', 0, 'warning', '', '', '1', '2025-07-02 09:46:09', '\"1\"', '2025-07-02 09:46:27', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3021, 1, 'IP 定位', '1', 'iot_location_type', 0, '', '', '', '1', '2025-07-05 09:56:46', '1', '2025-07-05 09:56:46', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3022, 2, '设备上报', '2', 'iot_location_type', 0, '', '', '', '1', '2025-07-05 09:56:57', '1', '2025-07-05 09:56:57', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3023, 3, '手动定位', '3', 'iot_location_type', 0, '', '', '', '1', '2025-07-05 09:57:05', '1', '2025-07-05 09:57:05', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3024, 3, '设备事件上报', '3', 'iot_rule_scene_trigger_type_enum', 0, '', '', '', '1', '2025-07-06 10:28:29', '1', '2025-07-06 10:28:29', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3025, 4, '设备服务调用', '4', 'iot_rule_scene_trigger_type_enum', 0, '', '', '', '1', '2025-07-06 10:28:35', '1', '2025-07-06 10:28:35', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3026, 100, '定时触发', '100', 'iot_rule_scene_trigger_type_enum', 0, '', '', '', '1', '2025-07-06 10:28:48', '1', '2025-07-06 10:28:48', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3027, 101, '告警恢复', '101', 'iot_rule_scene_action_type_enum', 0, '', '', '', '1', '2025-07-06 10:37:57', '1', '2025-07-06 10:37:57', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3028, 2, 'Anthropic', 'Anthropic', 'ai_platform', 0, '', '', '', '1', '2025-08-21 22:54:24', '1', '2025-08-21 22:57:58', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3029, 2, '谷歌 Gemini', 'Gemini', 'ai_platform', 0, '', '', '', '1', '2025-08-22 22:39:35', '1', '2025-08-22 22:44:49', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3030, 1, '文件系统', 'filesystem', 'ai_mcp_client_name', 0, '', '', '', '1', '2025-08-28 13:58:43', '1', '2025-08-28 21:19:42', b'0');
COMMIT;
-- ----------------------------
@ -1076,7 +1103,7 @@ CREATE TABLE `system_dict_type` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`deleted_time` datetime NULL DEFAULT NULL COMMENT '删除时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2000 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表';
) ENGINE = InnoDB AUTO_INCREMENT = 2008 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表';
-- ----------------------------
-- Records of system_dict_type
@ -1175,20 +1202,24 @@ INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creat
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (628, 'AI 写作类型', 'ai_write_type', 0, '', '1', '2024-07-10 21:25:29', '1', '2024-07-10 21:25:29', b'0', '1970-01-01 00:00:00');
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (629, 'BPM 流程模型类型', 'bpm_model_type', 0, '', '1', '2024-08-26 15:21:43', '1', '2024-08-26 15:21:43', b'0', '1970-01-01 00:00:00');
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (640, 'AI 模型类型', 'ai_model_type', 0, '', '1', '2025-03-03 12:24:07', '1', '2025-03-03 12:24:07', b'0', '1970-01-01 00:00:00');
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1000, 'IoT 数据格式', 'iot_data_format', 0, '', '1', '2024-08-10 11:52:58', '1', '2025-03-17 09:25:06', b'0', '1970-01-01 00:00:00');
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1001, 'IoT 产品设备类型', 'iot_product_device_type', 0, '', '1', '2024-08-10 11:54:30', '1', '2025-03-17 09:25:08', b'0', '1970-01-01 00:00:00');
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1002, 'IoT 产品状态', 'iot_product_status', 0, '', '1', '2024-08-10 12:06:09', '1', '2025-03-17 09:25:10', b'0', '1970-01-01 00:00:00');
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1003, 'IoT 数据校验级别', 'iot_validate_type', 0, '', '1', '2024-09-06 20:05:13', '1', '2025-03-17 09:25:12', b'0', '1970-01-01 00:00:00');
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1004, 'IoT 联网方式', 'iot_net_type', 0, '', '1', '2024-09-06 22:04:13', '1', '2025-03-17 09:25:14', b'0', '1970-01-01 00:00:00');
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1005, 'IoT 接入网关协议', 'iot_protocol_type', 0, '', '1', '2024-09-06 22:20:17', '1', '2025-03-17 09:25:16', b'0', '1970-01-01 00:00:00');
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1006, 'IoT 设备状态', 'iot_device_state', 0, '', '1', '2024-09-21 08:12:55', '1', '2025-03-17 09:25:19', b'0', '1970-01-01 00:00:00');
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1007, 'IoT 物模型功能类型', 'iot_thing_model_type', 0, '', '1', '2024-09-29 20:02:36', '1', '2025-03-17 09:25:24', b'0', '1970-01-01 00:00:00');
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1008, 'IoT 插件部署方式', 'iot_plugin_deploy_type', 0, '', '1', '2024-12-13 10:55:13', '1', '2025-03-17 09:25:27', b'0', '1970-01-01 00:00:00');
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1009, 'IoT 插件状态', 'iot_plugin_status', 0, '', '1', '2024-12-13 11:05:34', '1', '2025-03-17 09:25:30', b'0', '1970-01-01 00:00:00');
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1010, 'IoT 插件类型', 'iot_plugin_type', 0, '', '1', '2024-12-13 11:08:19', '1', '2025-03-17 09:25:32', b'0', '1970-01-01 00:00:00');
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1011, 'IoT 物模型单位', 'iot_thing_model_unit', 0, '', '1', '2024-12-25 17:36:46', '1', '2025-03-17 09:25:35', b'0', '1970-01-01 00:00:00');
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1012, 'IoT 数据桥接的方向枚举', 'iot_data_bridge_direction_enum', 0, '', '1', '2025-03-09 12:37:40', '1', '2025-03-17 09:25:39', b'0', '1970-01-01 00:00:00');
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1013, 'IoT 数据桥梁的类型枚举', 'iot_data_bridge_type_enum', 0, '', '1', '2025-03-09 12:39:36', '1', '2025-04-06 17:09:46', b'0', '1970-01-01 00:00:00');
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1013, 'IoT 数据流转目的的类型枚举', 'iot_data_sink_type_enum', 0, '', '1', '2025-03-09 12:39:36', '1', '2025-06-24 12:45:24', b'0', '1970-01-01 00:00:00');
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1014, 'IoT 场景流转的触发类型枚举', 'iot_rule_scene_trigger_type_enum', 0, '', '1', '2025-03-20 14:59:44', '1', '2025-03-20 14:59:44', b'0', '1970-01-01 00:00:00');
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1015, 'IoT 设备消息类型枚举', 'iot_device_message_type_enum', 0, '', '1', '2025-03-20 15:01:15', '1', '2025-03-20 15:01:15', b'0', '1970-01-01 00:00:00');
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1016, 'IoT 规则场景的触发类型枚举', 'iot_rule_scene_action_type_enum', 0, '', '1', '2025-03-28 15:26:54', '1', '2025-03-28 15:29:13', b'0', '1970-01-01 00:00:00');
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (2000, 'IoT 数据格式', 'iot_codec_type', 0, 'IoT 编解码器类型', '1', '2025-06-12 22:55:46', '1', '2025-06-12 22:55:46', b'0', '1970-01-01 00:00:00');
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (2001, 'IoT 告警级别', 'iot_alert_level', 0, '', '1', '2025-06-27 20:30:57', '1', '2025-06-27 20:30:57', b'0', '1970-01-01 00:00:00');
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (2002, 'IoT 告警', 'iot_alert_receive_type', 0, '', '1', '2025-06-27 22:49:19', '1', '2025-06-27 22:49:19', b'0', '1970-01-01 00:00:00');
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (2003, 'IoT 固件设备范围', 'iot_ota_task_device_scope', 0, '', '1', '2025-07-02 09:42:49', '1', '2025-07-02 09:42:49', b'0', '1970-01-01 00:00:00');
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (2004, 'IoT 固件升级任务状态', 'iot_ota_task_status', 0, '', '1', '2025-07-02 09:43:43', '1', '2025-07-02 09:43:43', b'0', '1970-01-01 00:00:00');
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (2005, 'IoT 固件升级记录状态', 'iot_ota_task_record_status', 0, '', '1', '2025-07-02 09:45:02', '1', '2025-07-02 09:45:02', b'0', '1970-01-01 00:00:00');
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (2006, 'IoT 定位类型', 'iot_location_type', 0, '', '1', '2025-07-05 09:56:25', '1', '2025-07-05 09:56:25', b'0', '1970-01-01 00:00:00');
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (2007, 'AI MCP 客户端名字', 'ai_mcp_client_name', 0, '', '1', '2025-08-28 13:57:40', '1', '2025-08-28 13:57:40', b'0', '1970-01-01 00:00:00');
COMMIT;
-- ----------------------------
@ -1212,7 +1243,7 @@ CREATE TABLE `system_login_log` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3822 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录';
) ENGINE = InnoDB AUTO_INCREMENT = 4021 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录';
-- ----------------------------
-- Records of system_login_log
@ -1246,7 +1277,7 @@ CREATE TABLE `system_mail_account` (
-- ----------------------------
BEGIN;
INSERT INTO `system_mail_account` (`id`, `mail`, `username`, `password`, `host`, `port`, `ssl_enable`, `starttls_enable`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, '7684413@qq.com', '7684413@qq.com', '1234576', '127.0.0.1', 8080, b'0', b'0', '1', '2023-01-25 17:39:52', '1', '2025-04-04 16:34:40', b'0');
INSERT INTO `system_mail_account` (`id`, `mail`, `username`, `password`, `host`, `port`, `ssl_enable`, `starttls_enable`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2, 'ydym_test@163.com', 'ydym_test@163.com', 'WBZTEINMIFVRYSOE', 'smtp.163.com', 465, b'1', b'0', '1', '2023-01-26 01:26:03', '1', '2023-04-12 22:39:38', b'0');
INSERT INTO `system_mail_account` (`id`, `mail`, `username`, `password`, `host`, `port`, `ssl_enable`, `starttls_enable`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2, 'ydym_test@163.com', 'ydym_test@163.com', 'WBZTEINMIFVRYSOE', 'smtp.163.com', 465, b'1', b'0', '1', '2023-01-26 01:26:03', '1', '2025-07-26 21:57:55', b'0');
INSERT INTO `system_mail_account` (`id`, `mail`, `username`, `password`, `host`, `port`, `ssl_enable`, `starttls_enable`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3, '76854114@qq.com', '3335', '11234', 'yunai1.cn', 466, b'0', b'0', '1', '2023-01-27 15:06:38', '1', '2023-01-27 07:08:36', b'1');
INSERT INTO `system_mail_account` (`id`, `mail`, `username`, `password`, `host`, `port`, `ssl_enable`, `starttls_enable`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4, '7685413x@qq.com', '2', '3', '4', 5, b'1', b'0', '1', '2023-04-12 23:05:06', '1', '2023-04-12 15:05:11', b'1');
COMMIT;
@ -1260,8 +1291,8 @@ CREATE TABLE `system_mail_log` (
`user_id` bigint NULL DEFAULT NULL COMMENT '用户编号',
`user_type` tinyint NULL DEFAULT NULL COMMENT '用户类型',
`to_mails` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '接收邮箱地址',
`cc_mails` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '抄送邮箱地址',
`bcc_mails` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '密送邮箱地址',
`cc_mails` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '抄送邮箱地址',
`bcc_mails` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '密送邮箱地址',
`account_id` bigint NOT NULL COMMENT '邮箱账号编号',
`from_mail` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '发送邮箱地址',
`template_id` bigint NOT NULL COMMENT '模板编号',
@ -1280,7 +1311,7 @@ CREATE TABLE `system_mail_log` (
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 360 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '邮件日志表';
) ENGINE = InnoDB AUTO_INCREMENT = 367 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '邮件日志表';
-- ----------------------------
-- Records of system_mail_log
@ -1316,8 +1347,8 @@ CREATE TABLE `system_mail_template` (
-- ----------------------------
BEGIN;
INSERT INTO `system_mail_template` (`id`, `name`, `code`, `account_id`, `nickname`, `title`, `content`, `params`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (13, '后台用户短信登录', 'admin-sms-login', 1, '奥特曼', '你猜我猜', '<p>您的验证码是{code},名字是{name}</p>', '[\"code\",\"name\"]', 0, '3', '1', '2021-10-11 08:10:00', '1', '2023-12-02 19:51:14', b'0');
INSERT INTO `system_mail_template` (`id`, `name`, `code`, `account_id`, `nickname`, `title`, `content`, `params`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (14, '测试模版', 'test_01', 2, '芋艿', '一个标题', '<p>你是 {key01} 吗?</p><p><br></p><p>是的话,赶紧 {key02} 一下!</p>', '[\"key01\",\"key02\"]', 0, NULL, '1', '2023-01-26 01:27:40', '1', '2023-01-27 10:32:16', b'0');
INSERT INTO `system_mail_template` (`id`, `name`, `code`, `account_id`, `nickname`, `title`, `content`, `params`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (15, '3', '2', 2, '7', '4', '<p>45</p>', '[]', 1, '80', '1', '2023-01-27 15:50:35', '1', '2023-01-27 16:34:49', b'0');
INSERT INTO `system_mail_template` (`id`, `name`, `code`, `account_id`, `nickname`, `title`, `content`, `params`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (14, '测试模版', 'test_01', 2, '芋艿', '一个标题', '<p>你是 {key01} 吗?</p><p><br></p><p>是的话,赶紧 {key02} 一下!</p>', '[\"key01\",\"key02\"]', 0, NULL, '1', '2023-01-26 01:27:40', '1', '2025-07-26 21:48:45', b'0');
INSERT INTO `system_mail_template` (`id`, `name`, `code`, `account_id`, `nickname`, `title`, `content`, `params`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (15, '3', '2', 2, '7', '4', '<p>45</p>', '[]', 1, '80', '1', '2023-01-27 15:50:35', '1', '2025-07-26 21:47:49', b'1');
COMMIT;
-- ----------------------------
@ -1345,7 +1376,7 @@ CREATE TABLE `system_menu` (
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5013 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '菜单权限表';
) ENGINE = InnoDB AUTO_INCREMENT = 5042 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '菜单权限表';
-- ----------------------------
-- Records of system_menu
@ -2203,55 +2234,47 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2924, '工具删除', 'ai:tool:delete', 3, 4, 2920, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2025-03-14 11:19:29', '', '2025-03-14 11:19:29', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4000, 'IoT 物联网', '', 1, 500, 0, '/iot', 'fa-solid:hdd', '', '', 0, b'1', b'1', b'1', '1', '2024-08-10 09:55:28', '1', '2024-12-07 15:58:34', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4001, '设备接入', '', 1, 2, 4000, 'device', 'ep:platform', '', '', 0, b'1', b'1', b'1', '1', '2024-08-10 09:57:56', '1', '2025-02-27 08:39:49', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4002, '产品管理', '', 2, 2, 4001, 'product', 'fa-solid:tools', 'iot/product/product/index', 'IoTProduct', 0, b'1', b'1', b'1', '', '2024-08-10 02:38:02', '1', '2024-12-07 18:47:53', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4002, '产品管理', '', 2, 1, 4001, 'product', 'fa-solid:tools', 'iot/product/product/index', 'IoTProduct', 0, b'1', b'1', b'1', '', '2024-08-10 02:38:02', '1', '2025-06-15 20:56:06', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4003, '产品查询', 'iot:product:query', 3, 1, 4002, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-08-10 02:38:02', '', '2024-12-07 15:55:00', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4004, '产品创建', 'iot:product:create', 3, 2, 4002, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-08-10 02:38:02', '', '2024-12-07 15:55:03', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4005, '产品更新', 'iot:product:update', 3, 3, 4002, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-08-10 02:38:02', '', '2024-12-07 15:55:05', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4006, '产品删除', 'iot:product:delete', 3, 4, 4002, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-08-10 02:38:02', '', '2024-12-07 15:55:06', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4007, '产品导出', 'iot:product:export', 3, 5, 4002, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-08-10 02:38:02', '', '2024-12-07 15:55:13', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4008, '设备管理', '', 2, 4, 4001, 'device', 'fa:mobile', 'iot/device/device/index', 'IoTDevice', 0, b'1', b'1', b'1', '', '2024-09-16 18:48:19', '1', '2024-12-14 11:39:30', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4008, '设备管理', '', 2, 2, 4001, 'device', 'fa:mobile', 'iot/device/device/index', 'IoTDevice', 0, b'1', b'1', b'1', '', '2024-09-16 18:48:19', '1', '2025-06-15 20:56:10', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4009, '设备查询', 'iot:device:query', 3, 1, 4008, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-09-16 18:48:19', '1', '2024-12-07 15:55:40', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4010, '设备创建', 'iot:device:create', 3, 2, 4008, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-09-16 18:48:19', '1', '2024-12-07 15:55:41', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4011, '设备更新', 'iot:device:update', 3, 3, 4008, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-09-16 18:48:19', '1', '2024-12-07 15:55:42', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4012, '设备删除', 'iot:device:delete', 3, 4, 4008, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-09-16 18:48:19', '1', '2024-12-07 15:55:43', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4013, '设备导出', 'iot:device:export', 3, 5, 4008, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-09-16 18:48:19', '1', '2024-12-07 15:55:44', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4014, '产品分类', '', 2, 1, 4001, 'product-category', 'ep:notebook', 'iot/product/category/index', 'IotProductCategory', 0, b'1', b'1', b'1', '', '2024-12-07 16:01:35', '1', '2024-12-07 16:31:52', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4014, '产品分类', '', 2, 3, 4001, 'product-category', 'ep:notebook', 'iot/product/category/index', 'IotProductCategory', 0, b'1', b'1', b'1', '', '2024-12-07 16:01:35', '1', '2025-06-15 20:56:39', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4015, '产品分类查询', 'iot:product-category:query', 3, 1, 4014, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-12-07 16:01:35', '', '2024-12-07 16:01:35', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4016, '产品分类创建', 'iot:product-category:create', 3, 2, 4014, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-12-07 16:01:35', '', '2024-12-07 16:01:35', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4017, '产品分类更新', 'iot:product-category:update', 3, 3, 4014, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-12-07 16:01:35', '', '2024-12-07 16:01:35', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4018, '产品分类删除', 'iot:product-category:delete', 3, 4, 4014, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-12-07 16:01:35', '', '2024-12-07 16:01:35', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4025, '插件管理', '', 2, 5, 4047, 'plugin-config', 'ep:folder-opened', 'iot/plugin/index', 'IoTPlugin', 0, b'1', b'1', b'1', '', '2024-12-09 21:25:06', '1', '2025-02-05 22:23:12', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4026, '插件查询', 'iot:plugin-config:query', 3, 1, 4025, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-12-09 21:25:06', '', '2025-02-05 21:23:20', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4027, '插件创建', 'iot:plugin-config:create', 3, 2, 4025, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-12-09 21:25:06', '', '2025-02-05 21:23:16', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4028, '插件更新', 'iot:plugin-config:update', 3, 3, 4025, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-12-09 21:25:06', '', '2025-02-05 21:23:12', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4029, '插件删除', 'iot:plugin-config:delete', 3, 4, 4025, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-12-09 21:25:06', '', '2025-02-05 21:23:09', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4030, '插件导出', 'iot:plugin-config:export', 3, 5, 4025, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-12-09 21:25:06', '', '2025-02-05 21:23:06', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4031, '设备分组', '', 2, 3, 4001, 'device-group', 'fa-solid:layer-group', 'iot/device/group/index', 'IotDeviceGroup', 0, b'1', b'1', b'1', '', '2024-12-14 17:08:29', '1', '2024-12-14 17:09:17', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4032, '设备分组查询', 'iot:device-group:query', 3, 1, 4031, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-12-14 17:08:29', '', '2024-12-14 17:08:29', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4033, '设备分组创建', 'iot:device-group:create', 3, 2, 4031, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-12-14 17:08:29', '', '2024-12-14 17:08:29', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4034, '设备分组更新', 'iot:device-group:update', 3, 3, 4031, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-12-14 17:08:29', '', '2024-12-14 17:08:29', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4035, '设备分组删除', 'iot:device-group:delete', 3, 4, 4031, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-12-14 17:08:29', '', '2024-12-14 17:08:29', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4036, '设备导入', 'iot:device:import', 3, 6, 4008, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-12-15 10:35:47', '1', '2024-12-15 10:35:47', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4037, '产品物模型', '', 2, 2, 4001, 'thing-model', 'ep:mostly-cloudy', 'iot/thingmodel/index', 'IoTThingModel', 0, b'0', b'0', b'0', '', '2024-12-16 17:17:50', '1', '2024-12-27 11:03:37', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4037, '产品物模型', '', 2, 99, 4001, 'thing-model', 'ep:mostly-cloudy', 'iot/thingmodel/index', 'IoTThingModel', 0, b'0', b'0', b'0', '', '2024-12-16 17:17:50', '1', '2025-06-15 20:56:19', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4038, '产品物模型功能查询', 'iot:thing-model:query', 3, 1, 4037, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-12-16 17:17:51', '', '2025-03-17 09:14:54', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4039, '产品物模型功能创建', 'iot:thing-model:create', 3, 2, 4037, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-12-16 17:17:52', '', '2025-03-17 09:14:58', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4040, '产品物模型功能更新', 'iot:thing-model:update', 3, 3, 4037, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-12-16 17:17:52', '', '2025-03-17 09:15:03', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4041, '产品物模型功能删除', 'iot:thing-model:delete', 3, 4, 4037, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-12-16 17:17:52', '', '2025-03-17 09:15:06', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4042, '产品物模型功能导出', 'iot:thing-model:export', 3, 5, 4037, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-12-16 17:17:53', '', '2025-03-17 09:15:09', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4043, '设备上行', 'iot:device:upstream', 3, 7, 4008, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-01-28 04:40:16', '1', '2025-01-31 22:45:53', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4043, '设备消息发送', 'iot:device:message-send', 3, 12, 4008, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-01-28 04:40:16', '1', '2025-06-14 14:09:26', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4044, '设备属性查询', 'iot:device:property-query', 3, 10, 4008, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-01-28 11:52:54', '1', '2025-01-28 11:52:54', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4045, '设备日志查询', 'iot:device:log-query', 3, 11, 4008, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-01-28 11:53:22', '1', '2025-01-28 11:53:22', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4046, '设备下行', 'iot:device:downstream', 3, 8, 4008, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-01-31 22:46:11', '1', '2025-01-31 22:46:11', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4047, '运维管理', '', 1, 2, 4000, 'operations', 'fa:cog', '', '', 0, b'1', b'1', b'1', '1', '2025-02-05 22:21:37', '1', '2025-02-05 22:22:53', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4045, '设备消息查询', 'iot:device:message-query', 3, 11, 4008, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-01-28 11:53:22', '1', '2025-06-14 11:11:20', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4047, '运维管理', '', 1, 4, 4000, 'operation', 'fa:align-center', '', '', 0, b'1', b'1', b'1', '1', '2025-02-05 22:21:37', '\"1\"', '2025-06-30 20:12:48', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4048, '规则引擎', '', 1, 3, 4000, 'rule', 'fa-solid:cogs', '', '', 0, b'1', b'1', b'1', '1', '2025-02-11 14:10:54', '1', '2025-02-11 14:10:54', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4049, '场景联动', '', 2, 1, 4048, 'scene', 'ep:link', 'iot/rule/scene/index', 'Scene', 0, b'1', b'1', b'1', '1', '2025-02-11 14:12:44', '1', '2025-02-12 10:15:36', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4050, 'IoT首页', '', 2, 1, 4000, 'home', 'ep:home-filled', 'iot/home/index', 'IotHome', 0, b'1', b'1', b'1', '1', '2025-02-27 08:39:35', '1', '2025-02-27 08:40:28', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4051, '数据桥梁', '', 2, 0, 4048, 'data-bridge', 'ep:guide', 'iot/rule/databridge/index', 'IotDataBridge', 0, b'1', b'1', b'1', '', '2025-03-09 13:47:11', '1', '2025-03-09 13:47:51', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4052, 'IoT 数据桥梁查询', 'iot:data-bridge:query', 3, 1, 4051, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2025-03-09 13:47:11', '', '2025-03-09 13:47:11', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4053, 'IoT 数据桥梁创建', 'iot:data-bridge:create', 3, 2, 4051, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2025-03-09 13:47:11', '', '2025-03-09 13:47:11', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4054, 'IoT 数据桥梁更新', 'iot:data-bridge:update', 3, 3, 4051, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2025-03-09 13:47:11', '', '2025-03-09 13:47:11', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4055, 'IoT 数据桥梁删除', 'iot:data-bridge:delete', 3, 4, 4051, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2025-03-09 13:47:12', '', '2025-03-09 13:47:12', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4056, 'IoT 数据桥梁导出', 'iot:data-bridge:export', 3, 5, 4051, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2025-03-09 13:47:12', '', '2025-03-09 13:47:12', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4049, '场景联动', '', 2, 1, 4048, 'scene', 'ep:link', 'iot/rule/scene/index', 'IoTSceneRule', 0, b'1', b'1', b'1', '1', '2025-02-11 14:12:44', '\"1\"', '2025-08-09 15:38:32', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4050, 'IoT 首页', '', 2, 1, 4000, 'home', 'ep:home-filled', 'iot/home/index', 'IotHome', 0, b'1', b'1', b'1', '1', '2025-02-27 08:39:35', '1', '2025-06-24 14:22:50', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4051, '数据流转', '', 2, 2, 4048, 'data-rule', 'ep:guide', 'iot/rule/data/index', 'IoTDataRule', 0, b'1', b'1', b'1', '', '2025-03-09 13:47:11', '\"1\"', '2025-08-09 15:38:37', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4052, '数据流转规则查询', 'iot:data-rule:query', 3, 1, 4051, '', '', '', '', 0, b'1', b'1', b'1', '', '2025-03-09 13:47:11', '1', '2025-06-24 20:48:04', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4053, '数据流转规则创建', 'iot:data-rule:create', 3, 2, 4051, '', '', '', '', 0, b'1', b'1', b'1', '', '2025-03-09 13:47:11', '1', '2025-06-24 20:48:08', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4054, '数据流转规则更新', 'iot:data-rule:update', 3, 3, 4051, '', '', '', '', 0, b'1', b'1', b'1', '', '2025-03-09 13:47:11', '1', '2025-06-24 20:48:11', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4055, '数据流转规则删除', 'iot:data-rule:delete', 3, 4, 4051, '', '', '', '', 0, b'1', b'1', b'1', '', '2025-03-09 13:47:12', '1', '2025-06-24 20:48:15', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5000, 'AI 工作流', '', 2, 5, 2758, 'workflow', 'fa:hand-grab-o', 'ai/workflow/index.vue', 'AiWorkflow', 0, b'1', b'1', b'1', '1', '2025-03-25 09:50:27', '1', '2025-05-03 18:55:12', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5001, 'AI 工作流查询', 'ai:workflow:query', 3, 1, 5000, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-03-25 09:51:11', '1', '2025-03-25 09:51:11', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5002, 'AI 工作流创建', 'ai:workflow:create', 3, 2, 5000, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-03-25 09:51:28', '1', '2025-03-25 09:51:28', b'0');
@ -2262,6 +2285,34 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5010, '租户切换', 'system:tenant:visit', 3, 999, 1138, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-05-05 15:25:32', '1', '2025-05-05 15:25:32', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5011, '转账订单查询', 'pay:transfer:query', 3, 1, 2559, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-05-08 12:46:53', '1', '2025-05-08 12:46:53', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5012, '转账订单导出', 'pay:transfer:export', 3, 2, 2559, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-05-10 17:00:28', '1', '2025-05-10 17:00:28', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5013, '场景联动查询', 'iot:rule-scene:query', 3, 1, 4049, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-06-20 16:53:01', '1', '2025-06-20 16:53:01', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5014, '场景联动创建', 'iot:rule-scene:create', 3, 2, 4049, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-06-20 16:54:31', '1', '2025-06-20 16:54:31', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5015, '场景联动更新', 'iot:rule-scene:update', 3, 3, 4049, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-06-20 16:54:47', '1', '2025-06-20 16:54:47', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5016, '场景联动删除', 'iot:rule-scene:delete', 3, 4, 4049, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-06-20 16:55:04', '1', '2025-06-20 16:55:27', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5017, '场景联动导出', 'iot:rule-scene:export', 3, 5, 4049, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-06-20 16:57:56', '1', '2025-06-20 16:57:56', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5018, '数据流转目的查询', 'iot:data-sink:query', 3, 11, 4051, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-06-24 20:48:40', '1', '2025-06-24 20:48:40', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5019, '数据流转目的创建', 'iot:data-sink:create', 3, 12, 4051, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-06-24 20:48:57', '1', '2025-06-24 20:48:57', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5020, '数据流转目的更新', 'iot:data-sink:update', 3, 13, 4051, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-06-24 20:49:10', '1', '2025-06-24 20:49:10', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5021, '数据流转目的删除', 'iot:data-sink:delete', 3, 14, 4051, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-06-24 20:49:23', '1', '2025-06-24 20:49:23', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5022, '告警配置', '', 2, 1, 5028, 'config', 'fa:connectdevelop', 'iot/alert/config/index', 'IotAlertConfig', 0, b'1', b'1', b'1', '', '2025-06-27 14:28:59', '1', '2025-06-27 22:31:19', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5023, '告警配置查询', 'iot:alert-config:query', 3, 1, 5022, '', '', '', '', 0, b'1', b'1', b'1', '', '2025-06-27 14:28:59', '1', '2025-06-28 16:00:31', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5024, '告警配置创建', 'iot:alert-config:create', 3, 2, 5022, '', '', '', '', 0, b'1', b'1', b'1', '', '2025-06-27 14:28:59', '1', '2025-06-28 16:00:35', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5025, '告警配置更新', 'iot:alert-config:update', 3, 3, 5022, '', '', '', '', 0, b'1', b'1', b'1', '', '2025-06-27 14:28:59', '1', '2025-06-28 16:00:43', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5026, '告警配置删除', 'iot:alert-config:delete', 3, 4, 5022, '', '', '', '', 0, b'1', b'1', b'1', '', '2025-06-27 14:29:00', '1', '2025-06-28 16:00:39', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5028, '告警中心', '', 1, 3, 4000, 'alert', 'fa:soundcloud', '', '', 0, b'1', b'1', b'1', '1', '2025-06-27 22:30:04', '1', '2025-06-27 22:30:19', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5029, '告警记录', '', 2, 2, 5028, 'record', 'fa-solid:record-vinyl', 'iot/alert/record/index', 'IotAlertRecord', 0, b'1', b'1', b'1', '', '2025-06-28 07:59:32', '1', '2025-06-28 16:01:48', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5030, '告警记录查询', 'iot:alert-record:query', 3, 1, 5029, '', '', '', '', 0, b'1', b'1', b'1', '', '2025-06-28 07:59:32', '1', '2025-06-28 16:00:53', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5031, '告警记录处理', 'iot:alert-record:process', 3, 2, 5029, '', '', '', '', 0, b'1', b'1', b'1', '', '2025-06-28 07:59:32', '1', '2025-06-28 16:01:04', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5032, 'OTA 固件', '', 2, 1, 4047, 'ota/firmware', 'fa-solid:award', 'iot/ota/firmware/index', 'IoTOtaFirmware', 0, b'1', b'1', b'1', '', '2025-06-30 07:50:29', '\"1\"', '2025-06-30 20:13:28', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5033, 'OTA 固件查询', 'iot:ota-firmware:query', 3, 1, 5032, '', '', '', '', 0, b'1', b'1', b'1', '', '2025-06-30 07:50:29', '\"1\"', '2025-06-30 17:38:12', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5034, 'OTA 固件创建', 'iot:ota-firmware:create', 3, 2, 5032, '', '', '', '', 0, b'1', b'1', b'1', '', '2025-06-30 07:50:29', '\"1\"', '2025-06-30 17:38:21', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5035, 'OTA 固件更新', 'iot:ota-firmware:update', 3, 3, 5032, '', '', '', '', 0, b'1', b'1', b'1', '', '2025-06-30 07:50:29', '\"1\"', '2025-06-30 17:38:29', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5036, 'OTA 固件删除', 'iot:ota-firmware:delete', 3, 4, 5032, '', '', '', '', 0, b'1', b'1', b'1', '', '2025-06-30 07:50:29', '\"1\"', '2025-06-30 17:38:37', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5037, 'OTA 升级任务查询', 'iot:ota-task:create', 3, 11, 5032, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-07-02 23:56:56', '1', '2025-07-02 23:56:56', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5038, 'OTA 升级任务取消', 'iot:ota-task:cancel', 3, 13, 5032, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-07-02 23:57:26', '1', '2025-07-02 23:57:26', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5039, 'OTA 升级任务创建', 'iot:ota-task:create', 3, 12, 5032, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-07-02 23:57:52', '1', '2025-07-02 23:57:52', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5040, 'OTA 升级记录查询', 'iot:ota-task-record:query', 3, 21, 5032, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-07-02 23:58:30', '1', '2025-07-02 23:58:30', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5041, 'OTA 升级记录取消', 'iot:ota-task-record:cancel', 3, 23, 5032, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-07-02 23:59:18', '1', '2025-07-02 23:59:18', b'0');
COMMIT;
-- ----------------------------
@ -2287,7 +2338,7 @@ CREATE TABLE `system_notice` (
-- Records of system_notice
-- ----------------------------
BEGIN;
INSERT INTO `system_notice` (`id`, `title`, `content`, `type`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, '芋道的公众', '<p>新版本内容133</p>', 1, 0, 'admin', '2021-01-05 17:03:48', '1', '2022-05-04 21:00:20', b'0', 1);
INSERT INTO `system_notice` (`id`, `title`, `content`, `type`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, '芋道的公众', '<p>新版本内容133222</p>', 1, 0, 'admin', '2021-01-05 17:03:48', '\"1\"', '2025-08-31 09:38:22', b'0', 1);
INSERT INTO `system_notice` (`id`, `title`, `content`, `type`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, '维护通知2018-07-01 系统凌晨维护', '<p><img src=\"http://test.yudao.iocoder.cn/b7cb3cf49b4b3258bf7309a09dd2f4e5.jpg\" alt=\"\" data-href=\"\">11112222<img src=\"http://test.yudao.iocoder.cn/fe44fc7bdb82ca421184b2eebbaee9e2148d4a1827479a4eb4521e11d2a062ba.png\" alt=\"image\" data-href=\"http://test.yudao.iocoder.cn/fe44fc7bdb82ca421184b2eebbaee9e2148d4a1827479a4eb4521e11d2a062ba.png\">3333</p>', 2, 1, 'admin', '2021-01-05 17:03:48', '1', '2025-04-18 23:56:40', b'0', 1);
INSERT INTO `system_notice` (`id`, `title`, `content`, `type`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4, '我是测试标题', '<p>哈哈哈哈123</p>', 1, 0, '110', '2022-02-22 01:01:25', '110', '2022-02-22 01:01:46', b'0', 121);
COMMIT;
@ -2383,7 +2434,7 @@ CREATE TABLE `system_oauth2_access_token` (
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_access_token`(`access_token` ASC) USING BTREE,
INDEX `idx_refresh_token`(`refresh_token` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 16697 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌';
) ENGINE = InnoDB AUTO_INCREMENT = 20179 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌';
-- ----------------------------
-- Records of system_oauth2_access_token
@ -2451,7 +2502,7 @@ CREATE TABLE `system_oauth2_client` (
-- Records of system_oauth2_client
-- ----------------------------
BEGIN;
INSERT INTO `system_oauth2_client` (`id`, `client_id`, `secret`, `name`, `logo`, `description`, `status`, `access_token_validity_seconds`, `refresh_token_validity_seconds`, `redirect_uris`, `authorized_grant_types`, `scopes`, `auto_approve_scopes`, `authorities`, `resource_ids`, `additional_information`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, 'default', 'admin123', '芋道源码', 'http://test.yudao.iocoder.cn/20250502/sort2_1746189740718.png', '我是描述', 0, 1800, 2592000, '[\"https://www.iocoder.cn\",\"https://doc.iocoder.cn\"]', '[\"password\",\"authorization_code\",\"implicit\",\"refresh_token\"]', '[\"user.read\",\"user.write\"]', '[]', '[\"user.read\",\"user.write\"]', '[]', '{}', '1', '2022-05-11 21:47:12', '1', '2025-05-02 20:42:22', b'0');
INSERT INTO `system_oauth2_client` (`id`, `client_id`, `secret`, `name`, `logo`, `description`, `status`, `access_token_validity_seconds`, `refresh_token_validity_seconds`, `redirect_uris`, `authorized_grant_types`, `scopes`, `auto_approve_scopes`, `authorities`, `resource_ids`, `additional_information`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, 'default', 'admin123', '芋道源码', 'http://test.yudao.iocoder.cn/20250502/sort2_1746189740718.png', '我是描述', 0, 1800, 2592000, '[\"https://www.iocoder.cn\",\"https://doc.iocoder.cn\"]', '[\"password\",\"authorization_code\",\"implicit\",\"refresh_token\",\"client_credentials\"]', '[\"user.read\",\"user.write\"]', '[]', '[\"user.read\",\"user.write\"]', '[]', '{}', '1', '2022-05-11 21:47:12', '1', '2025-08-21 10:04:50', b'0');
INSERT INTO `system_oauth2_client` (`id`, `client_id`, `secret`, `name`, `logo`, `description`, `status`, `access_token_validity_seconds`, `refresh_token_validity_seconds`, `redirect_uris`, `authorized_grant_types`, `scopes`, `auto_approve_scopes`, `authorities`, `resource_ids`, `additional_information`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (40, 'test', 'test2', 'biubiu', 'http://test.yudao.iocoder.cn/xx/20250502/ed07110a37464b5299f8bd7c67ad65c7_1746187077009.jpg', '啦啦啦啦', 0, 1800, 43200, '[\"https://www.iocoder.cn\"]', '[\"password\",\"authorization_code\",\"implicit\"]', '[\"user_info\",\"projects\"]', '[\"user_info\"]', '[]', '[]', '{}', '1', '2022-05-12 00:28:20', '1', '2025-05-02 19:58:08', b'0');
INSERT INTO `system_oauth2_client` (`id`, `client_id`, `secret`, `name`, `logo`, `description`, `status`, `access_token_validity_seconds`, `refresh_token_validity_seconds`, `redirect_uris`, `authorized_grant_types`, `scopes`, `auto_approve_scopes`, `authorities`, `resource_ids`, `additional_information`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (41, 'yudao-sso-demo-by-code', 'test', '基于授权码模式,如何实现 SSO 单点登录?', 'http://test.yudao.iocoder.cn/it/20250502/sign_1746181948685.png', NULL, 0, 1800, 43200, '[\"http://127.0.0.1:18080\"]', '[\"authorization_code\",\"refresh_token\"]', '[\"user.read\",\"user.write\"]', '[]', '[]', '[]', NULL, '1', '2022-09-29 13:28:31', '1', '2025-05-02 18:32:30', b'0');
INSERT INTO `system_oauth2_client` (`id`, `client_id`, `secret`, `name`, `logo`, `description`, `status`, `access_token_validity_seconds`, `refresh_token_validity_seconds`, `redirect_uris`, `authorized_grant_types`, `scopes`, `auto_approve_scopes`, `authorities`, `resource_ids`, `additional_information`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (42, 'yudao-sso-demo-by-password', 'test', '基于密码模式,如何实现 SSO 单点登录?', 'http://test.yudao.iocoder.cn/604bdc695e13b3b22745be704d1f2aa8ee05c5f26f9fead6d1ca49005afbc857.jpeg', NULL, 0, 1800, 43200, '[\"http://127.0.0.1:18080\"]', '[\"password\",\"refresh_token\"]', '[\"user.read\",\"user.write\"]', '[]', '[]', '[]', NULL, '1', '2022-10-04 17:40:16', '1', '2025-05-04 16:00:46', b'0');
@ -2505,7 +2556,7 @@ CREATE TABLE `system_oauth2_refresh_token` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2036 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 刷新令牌';
) ENGINE = InnoDB AUTO_INCREMENT = 2201 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 刷新令牌';
-- ----------------------------
-- Records of system_oauth2_refresh_token
@ -2539,7 +2590,7 @@ CREATE TABLE `system_operate_log` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 9090 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '操作日志记录 V2 版本';
) ENGINE = InnoDB AUTO_INCREMENT = 9134 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '操作日志记录 V2 版本';
-- ----------------------------
-- Records of system_operate_log
@ -2607,11 +2658,9 @@ BEGIN;
INSERT INTO `system_role` (`id`, `name`, `code`, `sort`, `data_scope`, `data_scope_dept_ids`, `status`, `type`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, '超级管理员', 'super_admin', 1, 1, '', 0, 1, '超级管理员', 'admin', '2021-01-05 17:03:48', '', '2022-02-22 05:08:21', b'0', 1);
INSERT INTO `system_role` (`id`, `name`, `code`, `sort`, `data_scope`, `data_scope_dept_ids`, `status`, `type`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, '普通角色', 'common', 2, 2, '', 0, 1, '普通角色', 'admin', '2021-01-05 17:03:48', '', '2022-02-22 05:08:20', b'0', 1);
INSERT INTO `system_role` (`id`, `name`, `code`, `sort`, `data_scope`, `data_scope_dept_ids`, `status`, `type`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3, 'CRM 管理员', 'crm_admin', 2, 1, '', 0, 1, 'CRM 专属角色', '1', '2024-02-24 10:51:13', '1', '2024-02-24 02:51:32', b'0', 1);
INSERT INTO `system_role` (`id`, `name`, `code`, `sort`, `data_scope`, `data_scope_dept_ids`, `status`, `type`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (101, '测试账号', 'test', 0, 1, '[]', 0, 2, '123', '', '2021-01-06 13:49:35', '1', '2025-04-30 17:38:28', b'0', 1);
INSERT INTO `system_role` (`id`, `name`, `code`, `sort`, `data_scope`, `data_scope_dept_ids`, `status`, `type`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (109, '租户管理员', 'tenant_admin', 0, 1, '', 0, 1, '系统自动生成', '1', '2022-02-22 00:56:14', '1', '2022-02-22 00:56:14', b'0', 121);
INSERT INTO `system_role` (`id`, `name`, `code`, `sort`, `data_scope`, `data_scope_dept_ids`, `status`, `type`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (111, '租户管理员', 'tenant_admin', 0, 1, '', 0, 1, '系统自动生成', '1', '2022-03-07 21:37:58', '1', '2022-03-07 21:37:58', b'0', 122);
INSERT INTO `system_role` (`id`, `name`, `code`, `sort`, `data_scope`, `data_scope_dept_ids`, `status`, `type`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (155, '测试数据权限', 'test-dp', 3, 2, '[100,102,103,104,105,108]', 0, 2, '', '1', '2025-03-31 14:58:06', '1', '2025-04-17 23:07:44', b'0', 1);
INSERT INTO `system_role` (`id`, `name`, `code`, `sort`, `data_scope`, `data_scope_dept_ids`, `status`, `type`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (158, '2', '3', 4, 1, '', 0, 2, NULL, '1', '2025-04-17 20:08:08', '1', '2025-04-17 23:05:31', b'0', 1);
COMMIT;
-- ----------------------------
@ -2670,87 +2719,6 @@ INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_t
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (707, 2, 113, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1296, 110, 1, '110', '2022-02-23 00:23:55', '110', '2022-02-23 00:23:55', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1578, 111, 1, '1', '2022-03-07 21:37:58', '1', '2022-03-07 21:37:58', b'0', 122);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1604, 101, 1216, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1605, 101, 1217, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1606, 101, 1218, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1607, 101, 1219, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1608, 101, 1220, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1609, 101, 1221, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1610, 101, 5, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1611, 101, 1222, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1612, 101, 1118, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1613, 101, 1119, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1614, 101, 1120, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1615, 101, 1185, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1616, 101, 1186, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1617, 101, 1187, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1618, 101, 1188, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1619, 101, 1189, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1620, 101, 1190, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1621, 101, 1191, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1622, 101, 1192, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1623, 101, 1193, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1624, 101, 1194, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1625, 101, 1195, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1627, 101, 1197, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1628, 101, 1198, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1629, 101, 1199, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1630, 101, 1200, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1631, 101, 1201, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1632, 101, 1202, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1633, 101, 1207, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1634, 101, 1208, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1635, 101, 1209, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1636, 101, 1210, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1637, 101, 1211, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1638, 101, 1212, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1639, 101, 1213, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1640, 101, 1215, '1', '2022-03-19 21:45:52', '1', '2022-03-19 21:45:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1641, 101, 2, '1', '2022-04-01 22:21:24', '1', '2022-04-01 22:21:24', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1642, 101, 1031, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1643, 101, 1032, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1644, 101, 1033, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1645, 101, 1034, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1646, 101, 1035, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1647, 101, 1050, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1648, 101, 1051, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1649, 101, 1052, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1650, 101, 1053, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1651, 101, 1054, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1652, 101, 1056, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1653, 101, 1057, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1654, 101, 1058, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1655, 101, 1059, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1656, 101, 1060, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1657, 101, 1066, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1658, 101, 1067, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1659, 101, 1070, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1664, 101, 1075, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1666, 101, 1077, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1667, 101, 1078, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1668, 101, 1082, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1669, 101, 1083, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1670, 101, 1084, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1671, 101, 1085, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1672, 101, 1086, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1673, 101, 1087, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1674, 101, 1088, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1675, 101, 1089, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1679, 101, 1237, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1680, 101, 1238, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1681, 101, 1239, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1682, 101, 1240, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1683, 101, 1241, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1684, 101, 1242, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1685, 101, 1243, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1687, 101, 106, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1688, 101, 110, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1689, 101, 111, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1690, 101, 112, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1691, 101, 113, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1692, 101, 114, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1693, 101, 115, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1694, 101, 116, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1729, 109, 100, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1730, 109, 101, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1731, 109, 1063, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', b'0', 121);
@ -3030,119 +2998,6 @@ INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_t
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2182, 2, 2016, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2183, 2, 2017, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2184, 2, 2018, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2188, 101, 1024, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2189, 101, 1, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2190, 101, 1025, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2191, 101, 1026, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2192, 101, 1027, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2193, 101, 1028, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2194, 101, 1029, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2195, 101, 1030, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2196, 101, 1036, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2197, 101, 1037, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2198, 101, 1038, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2199, 101, 1039, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2200, 101, 1040, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2201, 101, 1042, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2202, 101, 1043, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2203, 101, 1045, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2204, 101, 1046, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2205, 101, 1048, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2206, 101, 2083, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2207, 101, 1063, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2208, 101, 1064, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2209, 101, 1065, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2210, 101, 1093, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2211, 101, 1094, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2212, 101, 1095, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2213, 101, 1096, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2214, 101, 1097, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2215, 101, 1098, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2216, 101, 1100, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2217, 101, 1101, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2218, 101, 1102, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2219, 101, 1103, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2220, 101, 1104, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2221, 101, 1105, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2222, 101, 1106, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2223, 101, 2130, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2224, 101, 1107, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2225, 101, 2131, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2226, 101, 1108, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2227, 101, 2132, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2228, 101, 1109, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2229, 101, 2133, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2230, 101, 2134, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2232, 101, 2135, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2234, 101, 2136, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2236, 101, 2137, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2238, 101, 2138, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2240, 101, 2139, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2242, 101, 2140, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2243, 101, 2141, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2244, 101, 2142, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2245, 101, 2143, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2246, 101, 2144, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2247, 101, 2145, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2248, 101, 2146, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2249, 101, 2147, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2250, 101, 100, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2251, 101, 2148, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2252, 101, 101, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2253, 101, 2149, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2254, 101, 102, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2255, 101, 2150, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2256, 101, 103, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2257, 101, 2151, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2258, 101, 104, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2259, 101, 2152, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2260, 101, 105, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2261, 101, 107, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2262, 101, 108, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2263, 101, 109, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2264, 101, 1138, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2265, 101, 1139, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2266, 101, 1140, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2267, 101, 1141, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2268, 101, 1142, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2269, 101, 1143, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2270, 101, 1224, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2271, 101, 1225, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2272, 101, 1226, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2273, 101, 1227, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2274, 101, 1228, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2275, 101, 1229, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2282, 101, 1261, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2283, 101, 1263, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2284, 101, 1264, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2285, 101, 1265, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2286, 101, 1266, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2287, 101, 1267, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2288, 101, 1001, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2289, 101, 1002, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2290, 101, 1003, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2291, 101, 1004, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2292, 101, 1005, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2293, 101, 1006, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2294, 101, 1007, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2295, 101, 1008, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2296, 101, 1009, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2297, 101, 1010, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2298, 101, 1011, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2299, 101, 1012, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2300, 101, 500, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2301, 101, 1013, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2302, 101, 501, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2303, 101, 1014, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2304, 101, 1015, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2305, 101, 1016, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2306, 101, 1017, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2307, 101, 1018, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2308, 101, 1019, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2309, 101, 1020, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2310, 101, 1021, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2311, 101, 1022, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2312, 101, 1023, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2929, 109, 1224, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2930, 109, 1225, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2931, 109, 1226, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 121);
@ -3360,7 +3215,6 @@ INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_t
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4193, 109, 2730, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4194, 109, 1195, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4195, 109, 2731, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4196, 109, 1196, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4197, 109, 2732, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4198, 109, 1197, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4199, 109, 2733, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121);
@ -3419,7 +3273,6 @@ INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_t
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4252, 111, 2730, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4253, 111, 1195, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4254, 111, 2731, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4255, 111, 1196, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4256, 111, 2732, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4257, 111, 1197, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4258, 111, 2733, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
@ -3445,8 +3298,6 @@ INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_t
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4278, 111, 1220, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4279, 111, 1221, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4280, 111, 1222, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5777, 101, 2739, '1', '2024-04-30 09:38:37', '1', '2024-04-30 09:38:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5778, 101, 2740, '1', '2024-04-30 09:38:37', '1', '2024-04-30 09:38:37', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5779, 2, 2739, '1', '2024-07-07 20:39:38', '1', '2024-07-07 20:39:38', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5780, 2, 2740, '1', '2024-07-07 20:39:38', '1', '2024-07-07 20:39:38', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5781, 2, 2758, '1', '2024-07-07 20:39:38', '1', '2024-07-07 20:39:38', b'0', 1);
@ -3454,9 +3305,6 @@ INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_t
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5783, 2, 2362, '1', '2024-07-07 20:39:38', '1', '2024-07-07 20:39:38', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5784, 2, 2387, '1', '2024-07-07 20:39:38', '1', '2024-07-07 20:39:38', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5785, 2, 2030, '1', '2024-07-07 20:39:38', '1', '2024-07-07 20:39:38', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5786, 101, 2758, '1', '2024-07-07 20:39:55', '1', '2024-07-07 20:39:55', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5787, 101, 2759, '1', '2024-07-07 20:39:55', '1', '2024-07-07 20:39:55', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5788, 101, 2783, '1', '2024-07-07 20:39:55', '1', '2024-07-07 20:39:55', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5789, 109, 2739, '1', '2024-07-13 22:37:24', '1', '2024-07-13 22:37:24', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5790, 109, 2740, '1', '2024-07-13 22:37:24', '1', '2024-07-13 22:37:24', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5791, 111, 2739, '1', '2024-07-13 22:37:24', '1', '2024-07-13 22:37:24', b'0', 122);
@ -3477,7 +3325,6 @@ INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_t
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6115, 155, 4043, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6116, 155, 4044, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6117, 155, 4045, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6118, 155, 4046, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6119, 155, 4001, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6120, 155, 4002, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6121, 155, 4003, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', b'0', 1);
@ -3497,7 +3344,6 @@ INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_t
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6135, 155, 4017, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6136, 155, 4018, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6137, 155, 4031, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6138, 101, 5010, '1', '2025-05-05 17:49:17', '1', '2025-05-05 17:49:17', b'0', 1);
COMMIT;
-- ----------------------------
@ -3552,7 +3398,7 @@ CREATE TABLE `system_sms_code` (
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_mobile`(`mobile` ASC) USING BTREE COMMENT '手机号'
) ENGINE = InnoDB AUTO_INCREMENT = 666 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '手机验证码';
) ENGINE = InnoDB AUTO_INCREMENT = 681 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '手机验证码';
-- ----------------------------
-- Records of system_sms_code
@ -3593,7 +3439,7 @@ CREATE TABLE `system_sms_log` (
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1290 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信日志';
) ENGINE = InnoDB AUTO_INCREMENT = 1491 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信日志';
-- ----------------------------
-- Records of system_sms_log
@ -3726,7 +3572,7 @@ CREATE TABLE `system_social_user_bind` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 164 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交绑定表';
) ENGINE = InnoDB AUTO_INCREMENT = 165 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交绑定表';
-- ----------------------------
-- Records of system_social_user_bind
@ -3744,8 +3590,8 @@ CREATE TABLE `system_tenant` (
`contact_user_id` bigint NULL DEFAULT NULL COMMENT '联系人的用户编号',
`contact_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '联系人',
`contact_mobile` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '联系手机',
`status` tinyint NOT NULL DEFAULT 0 COMMENT '租户状态0正常 1停用',
`website` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '绑定域名',
`status` tinyint NOT NULL DEFAULT 0 COMMENT '租户状态',
`websites` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '绑定域名数组',
`package_id` bigint NOT NULL COMMENT '租户套餐编号',
`expire_time` datetime NOT NULL COMMENT '过期时间',
`account_count` int NOT NULL COMMENT '账号数量',
@ -3761,9 +3607,9 @@ CREATE TABLE `system_tenant` (
-- Records of system_tenant
-- ----------------------------
BEGIN;
INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `website`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, '芋道源码', NULL, '芋艿', '17321315478', 0, 'www.iocoder.cn', 0, '2099-02-19 17:14:16', 9999, '1', '2021-01-05 17:03:47', '1', '2023-11-06 11:41:41', b'0');
INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `website`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (121, '小租户', 110, '小王2', '15601691300', 0, 'zsxq.iocoder.cn', 111, '2026-07-10 00:00:00', 30, '1', '2022-02-22 00:56:14', '1', '2025-04-03 21:33:01', b'0');
INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `website`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (122, '测试租户', 113, '芋道', '15601691300', 0, 'test.iocoder.cn', 111, '2022-04-29 00:00:00', 50, '1', '2022-03-07 21:37:58', '1', '2024-09-22 12:10:50', b'0');
INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `websites`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, '芋道源码', NULL, '芋艿', '17321315478', 0, 'www.iocoder.cn,127.0.0.1:3000,wxc4598c446f8a9cb3', 0, '2099-02-19 17:14:16', 9999, '1', '2021-01-05 17:03:47', '1', '2025-08-19 05:18:41', b'0');
INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `websites`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (121, '小租户', 110, '小王2', '15601691300', 0, 'zsxq.iocoder.cn,123321', 111, '2026-07-10 00:00:00', 30, '1', '2022-02-22 00:56:14', '1', '2025-08-19 21:19:29', b'0');
INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `websites`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (122, '测试租户', 113, '芋道', '15601691300', 0, 'test.iocoder.cn', 111, '2022-04-29 00:00:00', 50, '1', '2022-03-07 21:37:58', '1', '2025-08-24 14:46:15', b'0');
COMMIT;
-- ----------------------------
@ -3788,8 +3634,7 @@ CREATE TABLE `system_tenant_package` (
-- Records of system_tenant_package
-- ----------------------------
BEGIN;
INSERT INTO `system_tenant_package` (`id`, `name`, `status`, `remark`, `menu_ids`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (111, '普通套餐', 0, '小功能', '[1,2,5,1031,1032,1033,1034,1035,1036,1037,1038,1039,1050,1051,1052,1053,1054,1056,1057,1058,1059,1060,1063,1064,1065,1066,1067,1070,1075,1077,1078,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1118,1119,1120,100,101,102,103,106,107,110,111,112,113,1138,114,1139,115,1140,116,1141,1142,1143,2713,2714,2715,2716,2717,2718,2720,1185,2721,1186,2722,1187,2723,1188,2724,1189,2725,1190,2726,1191,2727,2472,1192,2728,1193,2729,1194,2730,1195,2731,1196,2732,1197,2733,2478,1198,2734,2479,1199,2735,2480,1200,2481,1201,2482,1202,2483,2739,2484,2740,2485,2486,2487,1207,2488,1208,2489,1209,2490,1210,2491,1211,2492,1212,2493,1213,2494,2495,1215,1216,2497,1217,1218,1219,1220,1221,1222,1224,1225,1226,1227,1228,1229,1237,1238,1239,1240,1241,1242,1243,2525,1255,1256,1001,1257,1002,1258,1003,1259,1004,1260,1005,1006,1007,1008,1009,1010,1011,1012,1013,1014,1015,1016,1017,1018,1019,1020]', '1', '2022-02-22 00:54:00', '1', '2024-07-13 22:37:24', b'0');
INSERT INTO `system_tenant_package` (`id`, `name`, `status`, `remark`, `menu_ids`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (112, '再来一个套餐', 0, '1234', '[1024,1,1025,1026,2,1027,1028,1029,1030,1031,1032,1033,1034,1035,1036,1037,1038,1039,1040,1042,1043,1045,1046,1048,1050,1051,1052,1053,1054,1056,1057,1058,2083,1059,1060,1063,1064,1065,1066,1067,1070,1075,1077,1078,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1100,1101,1102,1103,1104,1105,1106,2130,1107,2131,1108,2132,1109,2133,2134,2135,2136,2137,2138,2139,2140,2141,2142,2143,2144,2145,2146,2147,100,2148,101,2149,102,2150,103,2151,104,2152,105,106,107,108,109,110,111,112,113,1138,114,1139,115,1140,116,1141,1142,1143,2739,2740,1224,1225,1226,1227,1228,1229,1237,1238,1239,1240,1241,1242,1243,1255,1256,1257,1258,1259,1260,1261,1263,1264,1265,1266,1267,2447,2448,2449,2450,2451,2452,2453,2472,2478,2479,2480,2481,2482,2483,2484,2485,2486,2487,2488,2489,2490,2491,2492,2493,2494,2495,2497,2525,1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1011,1012,500,1013,501,1014,1015,1016,1017,1018,1019,1020,1021,1022,1023]', '1', '2025-04-04 08:15:02', '1', '2025-04-04 08:15:21', b'0');
INSERT INTO `system_tenant_package` (`id`, `name`, `status`, `remark`, `menu_ids`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (111, '普通套餐', 0, '小功能', '[1,2,5,1031,1032,1033,1034,1035,1036,1037,1038,1039,1050,1051,1052,1053,1054,1056,1057,1058,1059,1060,1063,1064,1065,1066,1067,1070,1075,1077,1078,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1118,1119,1120,100,101,102,103,106,107,110,111,112,113,114,1138,1139,115,1140,116,1141,1142,1143,2713,2714,2715,2716,2717,2718,2720,2721,1185,2722,1186,1187,2723,1188,2724,1189,2725,1190,2726,1191,2727,2472,1192,2728,2729,1193,1194,2730,1195,2731,2732,1197,2733,2478,1198,2734,2479,1199,2735,2480,1200,2481,1201,2482,1202,2739,2483,2484,2740,2485,2486,2487,1207,2488,1208,2489,1209,2490,1210,2491,1211,2492,1212,2493,1213,2494,2495,1215,1216,2497,1217,1218,1219,1220,1221,1222,1224,1225,1226,1227,1228,1229,1237,1238,1239,1240,1241,1242,1243,2525,1255,1256,1001,1257,1002,1258,1003,1259,1004,1260,1005,1006,1007,1008,1009,1010,1011,1012,1013,1014,1015,1016,1017,1018,1019,1020]', '1', '2022-02-22 00:54:00', '1', '2025-05-14 14:06:34', b'0');
COMMIT;
-- ----------------------------
@ -3839,7 +3684,7 @@ CREATE TABLE `system_user_role` (
`deleted` bit(1) NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 49 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户和角色关联表';
) ENGINE = InnoDB AUTO_INCREMENT = 50 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户和角色关联表';
-- ----------------------------
-- Records of system_user_role
@ -3847,7 +3692,6 @@ CREATE TABLE `system_user_role` (
BEGIN;
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 1, 1, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:17', b'0', 1);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, 2, 2, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:13', b'0', 1);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4, 100, 101, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:13', b'0', 1);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5, 100, 1, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:12', b'0', 1);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6, 100, 2, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:11', b'0', 1);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (10, 103, 1, '1', '2022-01-11 13:19:45', '1', '2022-01-11 13:19:45', b'0', 1);
@ -3858,10 +3702,10 @@ INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_t
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (22, 115, 2, '1', '2022-07-21 22:08:30', '1', '2022-07-21 22:08:30', b'0', 1);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (35, 112, 1, '1', '2024-03-15 20:00:24', '1', '2024-03-15 20:00:24', b'0', 1);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (36, 118, 1, '1', '2024-03-17 09:12:08', '1', '2024-03-17 09:12:08', b'0', 1);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (38, 114, 101, '1', '2024-03-24 22:23:03', '1', '2024-03-24 22:23:03', b'0', 1);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (46, 117, 1, '1', '2024-10-02 10:16:11', '1', '2024-10-02 10:16:11', b'0', 1);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (47, 104, 2, '1', '2025-01-04 10:40:33', '1', '2025-01-04 10:40:33', b'0', 1);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (48, 100, 155, '1', '2025-04-04 10:41:14', '1', '2025-04-04 10:41:14', b'0', 1);
INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (49, 142, 1, '1', '2025-07-23 09:11:42', '1', '2025-07-23 09:11:42', b'0', 1);
COMMIT;
-- ----------------------------
@ -3890,15 +3734,15 @@ CREATE TABLE `system_users` (
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 142 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户信息表';
) ENGINE = InnoDB AUTO_INCREMENT = 143 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户信息表';
-- ----------------------------
-- Records of system_users
-- ----------------------------
BEGIN;
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 'admin', '$2a$04$KljJDa/LK7QfDm0lF5OhuePhlPfjRH3tB2Wu351Uidz.oQGJXevPi', '芋道源码', '管理员', 103, '[1,2]', '11aoteman@126.com', '18818260277', 2, 'http://test.yudao.iocoder.cn/test/20250502/avatar_1746154660449.png', 0, '0:0:0:0:0:0:0:1', '2025-05-10 18:03:15', 'admin', '2021-01-05 17:03:47', NULL, '2025-05-10 18:03:15', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 'admin', '$2a$04$KljJDa/LK7QfDm0lF5OhuePhlPfjRH3tB2Wu351Uidz.oQGJXevPi', '芋道源码', '管理员', 103, '[1,2]', '11aoteman@126.com', '18818260272', 2, 'http://test.yudao.iocoder.cn/user/avatar/20250709/blob_1752042302026.jpg', 0, '0:0:0:0:0:0:0:1', '2025-08-30 19:57:52', 'admin', '2021-01-05 17:03:47', NULL, '2025-08-30 19:57:52', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (100, 'yudao', '$2a$04$h.aaPKgO.odHepnk5PCsWeEwKdojFWdTItxGKfx1r0e1CSeBzsTJ6', '芋道', '不要吓我', 104, '[1]', 'yudao@iocoder.cn', '15601691300', 1, NULL, 0, '0:0:0:0:0:0:0:1', '2025-04-08 09:36:40', '', '2021-01-07 09:07:17', NULL, '2025-04-21 14:23:08', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (103, 'yuanma', '$2a$04$fUBSmjKCPYAUmnMzOb6qE.eZCGPhHi1JmAKclODbfS/O7fHOl2bH6', '源码', NULL, 106, NULL, 'yuanma@iocoder.cn', '15601701300', 0, NULL, 0, '0:0:0:0:0:0:0:1', '2024-08-11 17:48:12', '', '2021-01-13 23:50:35', NULL, '2025-04-21 14:23:08', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (103, 'yuanma', '$2a$04$fUBSmjKCPYAUmnMzOb6qE.eZCGPhHi1JmAKclODbfS/O7fHOl2bH6', '源码', NULL, 106, NULL, 'yuanma@iocoder.cn', '15601701300', 0, NULL, 0, '0:0:0:0:0:0:0:1', '2024-08-11 17:48:12', '', '2021-01-13 23:50:35', '1', '2025-07-09 23:41:58', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (104, 'test', '$2a$04$BrwaYn303hjA/6TnXqdGoOLhyHOAA0bVrAFu6.1dJKycqKUnIoRz2', '测试号', NULL, 107, '[1,2]', '111@qq.com', '15601691200', 1, NULL, 0, '0:0:0:0:0:0:0:1', '2025-03-28 20:01:16', '', '2021-01-21 02:13:53', NULL, '2025-04-21 14:23:08', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (107, 'admin107', '$2a$10$dYOOBKMO93v/.ReCqzyFg.o67Tqk.bbc2bhrpyBGkIw9aypCtr2pm', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, NULL, 0, '', NULL, '1', '2022-02-20 22:59:33', '1', '2025-04-21 14:23:08', b'0', 118);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (108, 'admin108', '$2a$10$y6mfvKoNYL1GXWak8nYwVOH.kCWqjactkzdoIDgiKl93WN3Ejg.Lu', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, NULL, 0, '', NULL, '1', '2022-02-20 23:00:50', '1', '2025-04-21 14:23:08', b'0', 119);
@ -3909,11 +3753,11 @@ INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`,
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (113, 'aoteman', '$2a$10$0acJOIk2D25/oC87nyclE..0lzeu9DtQ/n3geP4fkun/zIVRhHJIO', '芋道1', NULL, NULL, NULL, '', '15601691300', 0, NULL, 0, '127.0.0.1', '2022-03-19 18:38:51', '1', '2022-03-07 21:37:58', '1', '2025-05-05 15:30:53', b'0', 122);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (114, 'hrmgr', '$2a$10$TR4eybBioGRhBmDBWkqWLO6NIh3mzYa8KBKDDB5woiGYFVlRAi.fu', 'hr 小姐姐', NULL, NULL, '[5]', '', '15601691236', 1, NULL, 0, '0:0:0:0:0:0:0:1', '2024-03-24 22:21:05', '1', '2022-03-19 21:50:58', NULL, '2025-04-21 14:23:08', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (115, 'aotemane', '$2a$04$GcyP0Vyzb2F2Yni5PuIK9ueGxM0tkZGMtDwVRwrNbtMvorzbpNsV2', '阿呆', '11222', 102, '[1,2]', '7648@qq.com', '15601691229', 2, NULL, 0, '', NULL, '1', '2022-04-30 02:55:43', '1', '2025-04-21 14:23:08', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (117, 'admin123', '$2a$04$sEtimsHu9YCkYY4/oqElHem2Ijc9ld20eYO6lN.g/21NfLUTDLB9W', '测试号02', '1111', 100, '[2]', '', '15601691234', 1, NULL, 0, '0:0:0:0:0:0:0:1', '2024-10-02 10:16:20', '1', '2022-07-09 17:40:26', NULL, '2025-04-21 14:23:08', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (118, 'goudan', '$2a$04$jth0yOj8cSJq84D6vrzusOHDwW/LpBfgBnQ6bfFlD8zNZfM632Ta2', '狗蛋', NULL, 103, '[1]', '', '15601691239', 1, NULL, 0, '0:0:0:0:0:0:0:1', '2024-03-17 09:10:27', '1', '2022-07-09 17:44:43', '1', '2025-04-21 14:23:08', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (131, 'hh', '$2a$04$jyH9h6.gaw8mpOjPfHIpx.8as2Rzfcmdlj5rlJFwgCw4rsv/MTb2K', '呵呵', NULL, 100, '[]', '777@qq.com', '15601882312', 1, NULL, 0, '', NULL, '1', '2024-04-27 08:45:56', '1', '2025-04-21 14:23:08', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (117, 'admin123', '$2a$04$sEtimsHu9YCkYY4/oqElHem2Ijc9ld20eYO6lN.g/21NfLUTDLB9W', '测试号02', '1111', 100, '[2]', '', '15601691234', 1, NULL, 0, '0:0:0:0:0:0:0:1', '2024-10-02 10:16:20', '1', '2022-07-09 17:40:26', '1', '2025-05-14 09:56:04', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (118, 'goudan', '$2a$04$jth0yOj8cSJq84D6vrzusOHDwW/LpBfgBnQ6bfFlD8zNZfM632Ta2', '狗蛋', NULL, 103, '[1]', '', '15601691239', 1, NULL, 0, '0:0:0:0:0:0:0:1', '2024-03-17 09:10:27', '1', '2022-07-09 17:44:43', '1', '2025-07-09 23:52:36', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (139, 'wwbwwb', '$2a$04$aOHoFbQU6zfBk/1Z9raF/ugTdhjNdx7culC1HhO0zvoczAnahCiMq', '小秃头', NULL, NULL, NULL, '', '', 0, NULL, 0, '0:0:0:0:0:0:0:1', '2024-09-10 21:03:58', NULL, '2024-09-10 21:03:58', NULL, '2025-04-21 14:23:08', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (141, 'admin1', '$2a$04$oj6F6d7HrZ70kYVD3TNzEu.m3TPUzajOVuC66zdKna8KRerK1FmVa', '新用户', NULL, NULL, NULL, '', '', 0, '', 0, '0:0:0:0:0:0:0:1', '2025-04-08 13:09:07', '1', '2025-04-08 13:09:07', '1', '2025-04-08 13:09:07', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (141, 'admin1', '$2a$04$oj6F6d7HrZ70kYVD3TNzEu.m3TPUzajOVuC66zdKna8KRerK1FmVa', '新用户', NULL, NULL, NULL, '', '', 0, '', 0, '0:0:0:0:0:0:0:1', '2025-04-08 13:09:07', '1', '2025-04-08 13:09:07', '1', '2025-05-14 19:11:48', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (142, 'test01', '$2a$04$vxfBq9d3vVIfUbo6Dw7Mt.KOJfvG7RJ.l2/B3Kw09NtNyAZ1vbB1m', 'test01', '', NULL, '[]', '', '', 1, '', 0, '0:0:0:0:0:0:0:1', '2025-07-29 19:47:17', '1', '2025-07-09 21:07:10', NULL, '2025-07-29 19:47:17', b'0', 1);
COMMIT;
-- ----------------------------

View File

@ -4608,7 +4608,7 @@ CREATE TABLE system_tenant
contact_name varchar(30) NOT NULL,
contact_mobile varchar(500) NULL DEFAULT NULL,
status int2 NOT NULL DEFAULT 0,
website varchar(256) NULL DEFAULT '',
websites varchar(256) NULL DEFAULT '',
package_id int8 NOT NULL,
expire_time timestamp NOT NULL,
account_count int4 NOT NULL,
@ -4628,7 +4628,7 @@ COMMENT ON COLUMN system_tenant.contact_user_id IS '联系人的用户编号';
COMMENT ON COLUMN system_tenant.contact_name IS '联系人';
COMMENT ON COLUMN system_tenant.contact_mobile IS '联系手机';
COMMENT ON COLUMN system_tenant.status IS '租户状态0正常 1停用';
COMMENT ON COLUMN system_tenant.website IS '绑定域名';
COMMENT ON COLUMN system_tenant.websites IS '绑定域名数组';
COMMENT ON COLUMN system_tenant.package_id IS '租户套餐编号';
COMMENT ON COLUMN system_tenant.expire_time IS '过期时间';
COMMENT ON COLUMN system_tenant.account_count IS '账号数量';
@ -4644,9 +4644,9 @@ COMMENT ON TABLE system_tenant IS '租户表';
-- ----------------------------
-- @formatter:off
BEGIN;
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (1, '芋道源码', NULL, '芋艿', '17321315478', 0, 'www.iocoder.cn', 0, '2099-02-19 17:14:16', 9999, '1', '2021-01-05 17:03:47', '1', '2023-11-06 11:41:41', '0');
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (121, '小租户', 110, '小王2', '15601691300', 0, 'zsxq.iocoder.cn', 111, '2026-07-10 00:00:00', 30, '1', '2022-02-22 00:56:14', '1', '2025-04-03 21:33:01', '0');
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (122, '测试租户', 113, '芋道', '15601691300', 0, 'test.iocoder.cn', 111, '2022-04-29 00:00:00', 50, '1', '2022-03-07 21:37:58', '1', '2024-09-22 12:10:50', '0');
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, websites, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (1, '芋道源码', NULL, '芋艿', '17321315478', 0, 'www.iocoder.cn', 0, '2099-02-19 17:14:16', 9999, '1', '2021-01-05 17:03:47', '1', '2023-11-06 11:41:41', '0');
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, websites, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (121, '小租户', 110, '小王2', '15601691300', 0, 'zsxq.iocoder.cn', 111, '2026-07-10 00:00:00', 30, '1', '2022-02-22 00:56:14', '1', '2025-04-03 21:33:01', '0');
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, websites, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (122, '测试租户', 113, '芋道', '15601691300', 0, 'test.iocoder.cn', 111, '2022-04-29 00:00:00', 50, '1', '2022-03-07 21:37:58', '1', '2024-09-22 12:10:50', '0');
COMMIT;
-- @formatter:on

View File

@ -4495,7 +4495,7 @@ CREATE TABLE system_tenant
contact_name varchar2(30) NULL,
contact_mobile varchar2(500) DEFAULT NULL NULL,
status smallint DEFAULT 0 NOT NULL,
website varchar2(256) DEFAULT '' NULL,
websites varchar2(256) DEFAULT '' NULL,
package_id number NOT NULL,
expire_time date NOT NULL,
account_count number NOT NULL,
@ -4515,7 +4515,7 @@ COMMENT ON COLUMN system_tenant.contact_user_id IS '联系人的用户编号';
COMMENT ON COLUMN system_tenant.contact_name IS '联系人';
COMMENT ON COLUMN system_tenant.contact_mobile IS '联系手机';
COMMENT ON COLUMN system_tenant.status IS '租户状态0正常 1停用';
COMMENT ON COLUMN system_tenant.website IS '绑定域名';
COMMENT ON COLUMN system_tenant.websites IS '绑定域名数组';
COMMENT ON COLUMN system_tenant.package_id IS '租户套餐编号';
COMMENT ON COLUMN system_tenant.expire_time IS '过期时间';
COMMENT ON COLUMN system_tenant.account_count IS '账号数量';
@ -4530,9 +4530,9 @@ COMMENT ON TABLE system_tenant IS '租户表';
-- Records of system_tenant
-- ----------------------------
-- @formatter:off
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (1, '芋道源码', NULL, '芋艿', '17321315478', 0, 'www.iocoder.cn', 0, to_date('2099-02-19 17:14:16', 'SYYYY-MM-DD HH24:MI:SS'), 9999, '1', to_date('2021-01-05 17:03:47', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-06 11:41:41', 'SYYYY-MM-DD HH24:MI:SS'), '0');
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (121, '小租户', 110, '小王2', '15601691300', 0, 'zsxq.iocoder.cn', 111, to_date('2026-07-10 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), 30, '1', to_date('2022-02-22 00:56:14', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2025-04-03 21:33:01', 'SYYYY-MM-DD HH24:MI:SS'), '0');
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (122, '测试租户', 113, '芋道', '15601691300', 0, 'test.iocoder.cn', 111, to_date('2022-04-29 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), 50, '1', to_date('2022-03-07 21:37:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-09-22 12:10:50', 'SYYYY-MM-DD HH24:MI:SS'), '0');
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, websites, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (1, '芋道源码', NULL, '芋艿', '17321315478', 0, 'www.iocoder.cn', 0, to_date('2099-02-19 17:14:16', 'SYYYY-MM-DD HH24:MI:SS'), 9999, '1', to_date('2021-01-05 17:03:47', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-06 11:41:41', 'SYYYY-MM-DD HH24:MI:SS'), '0');
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, websites, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (121, '小租户', 110, '小王2', '15601691300', 0, 'zsxq.iocoder.cn', 111, to_date('2026-07-10 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), 30, '1', to_date('2022-02-22 00:56:14', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2025-04-03 21:33:01', 'SYYYY-MM-DD HH24:MI:SS'), '0');
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, websites, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (122, '测试租户', 113, '芋道', '15601691300', 0, 'test.iocoder.cn', 111, to_date('2022-04-29 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), 50, '1', to_date('2022-03-07 21:37:58', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2024-09-22 12:10:50', 'SYYYY-MM-DD HH24:MI:SS'), '0');
COMMIT;
-- @formatter:on

View File

@ -4608,7 +4608,7 @@ CREATE TABLE system_tenant
contact_name varchar(30) NOT NULL,
contact_mobile varchar(500) NULL DEFAULT NULL,
status int2 NOT NULL DEFAULT 0,
website varchar(256) NULL DEFAULT '',
websites varchar(256) NULL DEFAULT '',
package_id int8 NOT NULL,
expire_time timestamp NOT NULL,
account_count int4 NOT NULL,
@ -4628,7 +4628,7 @@ COMMENT ON COLUMN system_tenant.contact_user_id IS '联系人的用户编号';
COMMENT ON COLUMN system_tenant.contact_name IS '联系人';
COMMENT ON COLUMN system_tenant.contact_mobile IS '联系手机';
COMMENT ON COLUMN system_tenant.status IS '租户状态0正常 1停用';
COMMENT ON COLUMN system_tenant.website IS '绑定域名';
COMMENT ON COLUMN system_tenant.websites IS '绑定域名数组';
COMMENT ON COLUMN system_tenant.package_id IS '租户套餐编号';
COMMENT ON COLUMN system_tenant.expire_time IS '过期时间';
COMMENT ON COLUMN system_tenant.account_count IS '账号数量';
@ -4644,9 +4644,9 @@ COMMENT ON TABLE system_tenant IS '租户表';
-- ----------------------------
-- @formatter:off
BEGIN;
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (1, '芋道源码', NULL, '芋艿', '17321315478', 0, 'www.iocoder.cn', 0, '2099-02-19 17:14:16', 9999, '1', '2021-01-05 17:03:47', '1', '2023-11-06 11:41:41', '0');
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (121, '小租户', 110, '小王2', '15601691300', 0, 'zsxq.iocoder.cn', 111, '2026-07-10 00:00:00', 30, '1', '2022-02-22 00:56:14', '1', '2025-04-03 21:33:01', '0');
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (122, '测试租户', 113, '芋道', '15601691300', 0, 'test.iocoder.cn', 111, '2022-04-29 00:00:00', 50, '1', '2022-03-07 21:37:58', '1', '2024-09-22 12:10:50', '0');
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, websites, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (1, '芋道源码', NULL, '芋艿', '17321315478', 0, 'www.iocoder.cn', 0, '2099-02-19 17:14:16', 9999, '1', '2021-01-05 17:03:47', '1', '2023-11-06 11:41:41', '0');
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, websites, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (121, '小租户', 110, '小王2', '15601691300', 0, 'zsxq.iocoder.cn', 111, '2026-07-10 00:00:00', 30, '1', '2022-02-22 00:56:14', '1', '2025-04-03 21:33:01', '0');
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, websites, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (122, '测试租户', 113, '芋道', '15601691300', 0, 'test.iocoder.cn', 111, '2022-04-29 00:00:00', 50, '1', '2022-03-07 21:37:58', '1', '2024-09-22 12:10:50', '0');
COMMIT;
-- @formatter:on

View File

@ -10834,7 +10834,7 @@ CREATE TABLE system_tenant
contact_name nvarchar(30) NOT NULL,
contact_mobile nvarchar(500) DEFAULT NULL NULL,
status tinyint DEFAULT 0 NOT NULL,
website nvarchar(256) DEFAULT '' NULL,
websites nvarchar(256) DEFAULT '' NULL,
package_id bigint NOT NULL,
expire_time datetime2 NOT NULL,
account_count int NOT NULL,
@ -10965,11 +10965,11 @@ BEGIN TRANSACTION
GO
SET IDENTITY_INSERT system_tenant ON
GO
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (1, N'芋道源码', NULL, N'芋艿', N'17321315478', 0, N'www.iocoder.cn', 0, N'2099-02-19 17:14:16', 9999, N'1', N'2021-01-05 17:03:47', N'1', N'2023-11-06 11:41:41', N'0')
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, websites, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (1, N'芋道源码', NULL, N'芋艿', N'17321315478', 0, N'www.iocoder.cn', 0, N'2099-02-19 17:14:16', 9999, N'1', N'2021-01-05 17:03:47', N'1', N'2023-11-06 11:41:41', N'0')
GO
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (121, N'小租户', 110, N'小王2', N'15601691300', 0, N'zsxq.iocoder.cn', 111, N'2026-07-10 00:00:00', 30, N'1', N'2022-02-22 00:56:14', N'1', N'2025-04-03 21:33:01', N'0')
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, websites, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (121, N'小租户', 110, N'小王2', N'15601691300', 0, N'zsxq.iocoder.cn', 111, N'2026-07-10 00:00:00', 30, N'1', N'2022-02-22 00:56:14', N'1', N'2025-04-03 21:33:01', N'0')
GO
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, website, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (122, N'测试租户', 113, N'芋道', N'15601691300', 0, N'test.iocoder.cn', 111, N'2022-04-29 00:00:00', 50, N'1', N'2022-03-07 21:37:58', N'1', N'2024-09-22 12:10:50', N'0')
INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, websites, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (122, N'测试租户', 113, N'芋道', N'15601691300', 0, N'test.iocoder.cn', 111, N'2022-04-29 00:00:00', 50, N'1', N'2022-03-07 21:37:58', N'1', N'2024-09-22 12:10:50', N'0')
GO
SET IDENTITY_INSERT system_tenant OFF
GO

View File

@ -14,57 +14,58 @@
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
<properties>
<revision>2025.08-SNAPSHOT</revision>
<flatten-maven-plugin.version>1.6.0</flatten-maven-plugin.version>
<revision>2025.09-SNAPSHOT</revision>
<flatten-maven-plugin.version>1.7.2</flatten-maven-plugin.version>
<!-- 统一依赖管理 -->
<spring.boot.version>3.4.5</spring.boot.version>
<spring.boot.version>3.5.5</spring.boot.version>
<!-- Web 相关 -->
<springdoc.version>2.8.3</springdoc.version>
<knife4j.version>4.6.0</knife4j.version>
<springdoc.version>2.8.11</springdoc.version>
<knife4j.version>4.5.0</knife4j.version>
<!-- DB 相关 -->
<druid.version>1.2.24</druid.version>
<druid.version>1.2.27</druid.version>
<mybatis.version>3.5.19</mybatis.version>
<mybatis-plus.version>3.5.12</mybatis-plus.version>
<mybatis-plus.version>3.5.14</mybatis-plus.version>
<mybatis-plus-join.version>1.5.4</mybatis-plus-join.version>
<dynamic-datasource.version>4.3.1</dynamic-datasource.version>
<easy-trans.version>3.0.6</easy-trans.version>
<redisson.version>3.41.0</redisson.version>
<redisson.version>3.51.0</redisson.version>
<dm8.jdbc.version>8.1.3.140</dm8.jdbc.version>
<kingbase.jdbc.version>8.6.0</kingbase.jdbc.version>
<opengauss.jdbc.version>5.1.0</opengauss.jdbc.version>
<taos.version>3.3.3</taos.version>
<taos.version>3.7.3</taos.version>
<!-- 消息队列 -->
<rocketmq-spring.version>2.3.2</rocketmq-spring.version>
<rocketmq-spring.version>2.3.4</rocketmq-spring.version>
<!-- 服务保障相关 -->
<lock4j.version>2.2.7</lock4j.version>
<!-- 监控相关 -->
<skywalking.version>9.0.0</skywalking.version>
<spring-boot-admin.version>3.4.5</spring-boot-admin.version>
<skywalking.version>9.5.0</skywalking.version>
<spring-boot-admin.version>3.5.2</spring-boot-admin.version>
<opentracing.version>0.33.0</opentracing.version>
<!-- Test 测试相关 -->
<podam.version>8.0.2.RELEASE</podam.version>
<jedis-mock.version>1.1.8</jedis-mock.version>
<jedis-mock.version>1.1.11</jedis-mock.version>
<mockito-inline.version>5.2.0</mockito-inline.version>
<!-- Bpm 工作流相关 -->
<flowable.version>7.0.1</flowable.version>
<!-- 工具类相关 -->
<anji-plus-captcha.version>1.4.0</anji-plus-captcha.version>
<jsoup.version>1.18.3</jsoup.version>
<jsoup.version>1.21.2</jsoup.version>
<lombok.version>1.18.38</lombok.version>
<mapstruct.version>1.6.3</mapstruct.version>
<hutool-5.version>5.8.35</hutool-5.version>
<hutool-6.version>6.0.0-M19</hutool-6.version>
<fastexcel.version>1.2.0</fastexcel.version>
<hutool-5.version>5.8.40</hutool-5.version>
<hutool-6.version>6.0.0-M22</hutool-6.version>
<fastexcel.version>1.3.0</fastexcel.version>
<velocity.version>2.4.1</velocity.version>
<fastjson.version>1.2.83</fastjson.version>
<guava.version>33.4.8-jre</guava.version>
<transmittable-thread-local.version>2.14.5</transmittable-thread-local.version>
<commons-net.version>3.11.1</commons-net.version>
<commons-lang3.version>3.18.0</commons-lang3.version>
<jsch.version>0.1.55</jsch.version>
<tika-core.version>3.1.0</tika-core.version>
<tika-core.version>3.2.2</tika-core.version>
<ip2region.version>2.7.0</ip2region.version>
<bizlog-sdk.version>3.0.6</bizlog-sdk.version>
<netty.version>4.1.118.Final</netty.version>
<netty.version>4.2.4.Final</netty.version>
<mqtt.version>1.2.5</mqtt.version>
<pf4j-spring.version>0.9.0</pf4j-spring.version>
<vertx.version>4.5.13</vertx.version>
@ -72,9 +73,9 @@
<awssdk.version>2.30.14</awssdk.version>
<justauth.version>1.16.7</justauth.version>
<justauth-starter.version>1.4.0</justauth-starter.version>
<jimureport.version>2.0.0</jimureport.version>
<jimubi.version>1.9.5</jimubi.version>
<weixin-java.version>4.7.5.B</weixin-java.version>
<jimureport.version>2.1.1</jimureport.version>
<jimubi.version>2.1.0</jimubi.version>
<weixin-java.version>4.7.7-20250808.182223</weixin-java.version>
</properties>
<dependencyManagement>
@ -151,13 +152,19 @@
</dependency>
<dependency>
<groupId>com.github.xingfudeshi</groupId> <!-- TODO 芋艿https://github.com/xiaoymin/knife4j/issues/874 -->
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>${knife4j.version}</version>
<exclusions>
<exclusion>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-api</artifactId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>${springdoc.version}</version>
</dependency>
@ -518,13 +525,18 @@
<artifactId>commons-net</artifactId> <!-- 解决 ftp 连接 -->
<version>${commons-net.version}</version>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId> <!-- 解决 sftp 连接 -->
<version>${jsch.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version> <!-- 解决 CVE-2025-48924 漏洞 -->
</dependency>
<dependency>
<groupId>com.anji-plus</groupId>
<artifactId>captcha-spring-boot-starter</artifactId> <!-- 验证码,一般用于登录使用 -->
@ -599,6 +611,10 @@
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
</exclusion>
<exclusion>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
</exclusion>
</exclusions>
</dependency>

View File

@ -60,7 +60,7 @@
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-api</artifactId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<scope>provided</scope> <!-- 设置为 provided主要是 PageParam 使用到 -->
</dependency>

View File

@ -1,7 +1,6 @@
package cn.iocoder.yudao.framework.common.biz.system.oauth2.dto;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.time.LocalDateTime;
@ -12,7 +11,6 @@ import java.time.LocalDateTime;
* @author 芋道源码
*/
@Data
@Accessors(chain = true)
public class OAuth2AccessTokenRespDTO implements Serializable {
/**

View File

@ -47,8 +47,15 @@ public class HttpUtils {
return builder.build();
}
private String append(String base, Map<String, ?> query, boolean fragment) {
return append(base, query, null, fragment);
public static String removeUrlQuery(String url) {
if (!StrUtil.contains(url, '?')) {
return url;
}
UrlBuilder builder = UrlBuilder.of(url, Charset.defaultCharset());
// 移除 queryfragment
builder.setQuery(null);
builder.setFragment(null);
return builder.build();
}
/**

View File

@ -13,6 +13,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.Getter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
@ -30,6 +31,7 @@ import java.util.List;
@Slf4j
public class JsonUtils {
@Getter
private static ObjectMapper objectMapper = new ObjectMapper();
static {

View File

@ -44,8 +44,7 @@ import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.util.pattern.PathPattern;
import java.util.Map;
import java.util.Objects;
import java.util.*;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
@ -84,41 +83,13 @@ public class YudaoTenantAutoConfiguration {
// ========== WEB ==========
@Bean
public FilterRegistrationBean<TenantContextWebFilter> tenantContextWebFilter(TenantProperties tenantProperties) {
public FilterRegistrationBean<TenantContextWebFilter> tenantContextWebFilter() {
FilterRegistrationBean<TenantContextWebFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new TenantContextWebFilter());
registrationBean.setOrder(WebFilterOrderEnum.TENANT_CONTEXT_FILTER);
addIgnoreUrls(tenantProperties);
return registrationBean;
}
/**
* 如果 Controller 接口上 {@link TenantIgnore} 注解那么添加到忽略的 URL
*
* @param tenantProperties 租户配置
*/
private void addIgnoreUrls(TenantProperties tenantProperties) {
// 获得接口对应的 HandlerMethod 集合
RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping)
applicationContext.getBean("requestMappingHandlerMapping");
Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = requestMappingHandlerMapping.getHandlerMethods();
// 获得有 @TenantIgnore 注解的接口
for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : handlerMethodMap.entrySet()) {
HandlerMethod handlerMethod = entry.getValue();
if (!handlerMethod.hasMethodAnnotation(TenantIgnore.class)) {
continue;
}
// 添加到忽略的 URL
if (entry.getKey().getPatternsCondition() != null) {
tenantProperties.getIgnoreUrls().addAll(entry.getKey().getPatternsCondition().getPatterns());
}
if (entry.getKey().getPathPatternsCondition() != null) {
tenantProperties.getIgnoreUrls().addAll(
convertList(entry.getKey().getPathPatternsCondition().getPatterns(), PathPattern::getPatternString));
}
}
}
@Bean
public TenantVisitContextInterceptor tenantVisitContextInterceptor(TenantProperties tenantProperties,
SecurityFrameworkService securityFrameworkService) {
@ -146,12 +117,42 @@ public class YudaoTenantAutoConfiguration {
GlobalExceptionHandler globalExceptionHandler,
TenantFrameworkService tenantFrameworkService) {
FilterRegistrationBean<TenantSecurityWebFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new TenantSecurityWebFilter(tenantProperties, webProperties,
registrationBean.setFilter(new TenantSecurityWebFilter(webProperties, tenantProperties, getTenantIgnoreUrls(),
globalExceptionHandler, tenantFrameworkService));
registrationBean.setOrder(WebFilterOrderEnum.TENANT_SECURITY_FILTER);
return registrationBean;
}
/**
* 如果 Controller 接口上 {@link TenantIgnore} 注解则添加到忽略租户的 URL 集合中
*
* @return 忽略租户的 URL 集合
*/
private Set<String> getTenantIgnoreUrls() {
Set<String> ignoreUrls = new HashSet<>();
// 获得接口对应的 HandlerMethod 集合
RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping)
applicationContext.getBean("requestMappingHandlerMapping");
Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = requestMappingHandlerMapping.getHandlerMethods();
// 获得有 @TenantIgnore 注解的接口
for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : handlerMethodMap.entrySet()) {
HandlerMethod handlerMethod = entry.getValue();
if (!handlerMethod.hasMethodAnnotation(TenantIgnore.class) // 方法级
&& !handlerMethod.getBeanType().isAnnotationPresent(TenantIgnore.class)) { // 接口级
continue;
}
// 添加到忽略的 URL
if (entry.getKey().getPatternsCondition() != null) {
ignoreUrls.addAll(entry.getKey().getPatternsCondition().getPatterns());
}
if (entry.getKey().getPathPatternsCondition() != null) {
ignoreUrls.addAll(
convertList(entry.getKey().getPathPatternsCondition().getPatterns(), PathPattern::getPatternString));
}
}
return ignoreUrls;
}
// ========== MQ ==========
@Bean

View File

@ -75,7 +75,7 @@ public class TenantDatabaseInterceptor implements TenantLineHandler {
if (TenantBaseDO.class.isAssignableFrom(tableInfo.getEntityType())) {
return false;
}
// 如果添加了 @TenantIgnore 注解显然也不忽略租户
// 如果添加了 @TenantIgnore 注解忽略租户
TenantIgnore tenantIgnore = tableInfo.getEntityType().getAnnotation(TenantIgnore.class);
return tenantIgnore != null;
}

View File

@ -12,6 +12,7 @@ import org.springframework.beans.factory.config.BeanPostProcessor;
public class TenantRabbitMQInitializer implements BeanPostProcessor {
@Override
@SuppressWarnings("PatternVariableCanBeUsed")
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof RabbitTemplate) {
RabbitTemplate rabbitTemplate = (RabbitTemplate) bean;
@ -20,4 +21,4 @@ public class TenantRabbitMQInitializer implements BeanPostProcessor {
return bean;
}
}
}

View File

@ -17,6 +17,7 @@ import org.springframework.beans.factory.config.BeanPostProcessor;
public class TenantRocketMQInitializer implements BeanPostProcessor {
@Override
@SuppressWarnings("PatternVariableCanBeUsed")
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof DefaultRocketMQListenerContainer) {
DefaultRocketMQListenerContainer container = (DefaultRocketMQListenerContainer) bean;
@ -50,4 +51,4 @@ public class TenantRocketMQInitializer implements BeanPostProcessor {
consumerImpl.registerConsumeMessageHook(new TenantRocketMQConsumeMessageHook());
}
}
}

View File

@ -12,15 +12,16 @@ import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService;
import cn.iocoder.yudao.framework.web.config.WebProperties;
import cn.iocoder.yudao.framework.web.core.filter.ApiRequestFilter;
import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.AntPathMatcher;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.AntPathMatcher;
import java.io.IOException;
import java.util.Objects;
import java.util.Set;
/**
* 多租户 Security Web 过滤器
@ -35,17 +36,26 @@ public class TenantSecurityWebFilter extends ApiRequestFilter {
private final TenantProperties tenantProperties;
/**
* 允许忽略租户的 URL 列表
*
* 目的解决 <a href="https://gitee.com/zhijiantianya/yudao-cloud/issues/ICUQL9">修改配置会导致 @TenantIgnore Controller 接口过滤失效</>
*/
private final Set<String> ignoreUrls;
private final AntPathMatcher pathMatcher;
private final GlobalExceptionHandler globalExceptionHandler;
private final TenantFrameworkService tenantFrameworkService;
public TenantSecurityWebFilter(TenantProperties tenantProperties,
WebProperties webProperties,
public TenantSecurityWebFilter(WebProperties webProperties,
TenantProperties tenantProperties,
Set<String> ignoreUrls,
GlobalExceptionHandler globalExceptionHandler,
TenantFrameworkService tenantFrameworkService) {
super(webProperties);
this.tenantProperties = tenantProperties;
this.ignoreUrls = ignoreUrls;
this.pathMatcher = new AntPathMatcher();
this.globalExceptionHandler = globalExceptionHandler;
this.tenantFrameworkService = tenantFrameworkService;
@ -101,13 +111,20 @@ public class TenantSecurityWebFilter extends ApiRequestFilter {
}
private boolean isIgnoreUrl(HttpServletRequest request) {
String apiUri = request.getRequestURI().substring(request.getContextPath().length());
// 快速匹配保证性能
if (CollUtil.contains(tenantProperties.getIgnoreUrls(), request.getRequestURI())) {
if (CollUtil.contains(tenantProperties.getIgnoreUrls(), apiUri)
|| CollUtil.contains(ignoreUrls, apiUri)) {
return true;
}
// 逐个 Ant 路径匹配
for (String url : tenantProperties.getIgnoreUrls()) {
if (pathMatcher.match(url, request.getRequestURI())) {
if (pathMatcher.match(url, apiUri)) {
return true;
}
}
for (String url : ignoreUrls) {
if (pathMatcher.match(url, apiUri)) {
return true;
}
}

View File

@ -21,6 +21,7 @@ public class YudaoAsyncAutoConfiguration {
return new BeanPostProcessor() {
@Override
@SuppressWarnings("PatternVariableCanBeUsed")
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// 处理 ThreadPoolTaskExecutor
if (bean instanceof ThreadPoolTaskExecutor) {

View File

@ -1,11 +1,7 @@
package cn.iocoder.yudao.framework.tracer.config;
import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum;
import cn.iocoder.yudao.framework.tracer.core.aop.BizTraceAspect;
import cn.iocoder.yudao.framework.tracer.core.filter.TraceFilter;
import io.opentracing.Tracer;
import io.opentracing.util.GlobalTracer;
import org.apache.skywalking.apm.toolkit.opentracing.SkywalkingTracer;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@ -20,31 +16,28 @@ import org.springframework.context.annotation.Bean;
*/
@AutoConfiguration
@ConditionalOnClass(name = {
"org.apache.skywalking.apm.toolkit.opentracing.SkywalkingTracer",
"io.opentracing.Tracer"
"org.apache.skywalking.apm.toolkit.opentracing.SkywalkingTracer", // 来自 apm-toolkit-opentracing.jar
// "io.opentracing.Tracer", // 来自 opentracing-api.jar
"jakarta.servlet.Filter"
})
@EnableConfigurationProperties(TracerProperties.class)
@ConditionalOnProperty(prefix = "yudao.tracer", value = "enable", matchIfMissing = true)
public class YudaoTracerAutoConfiguration {
@Bean
public TracerProperties bizTracerProperties() {
return new TracerProperties();
}
@Bean
public BizTraceAspect bizTracingAop() {
return new BizTraceAspect(tracer());
}
@Bean
public Tracer tracer() {
// 创建 SkywalkingTracer 对象
SkywalkingTracer tracer = new SkywalkingTracer();
// 设置为 GlobalTracer 的追踪器
GlobalTracer.registerIfAbsent(tracer);
return tracer;
}
// TODO @芋艿skywalking 不兼容最新的 opentracing 版本同时opentracing 也停止了维护尬住了后续换 opentelemetry 即可
// @Bean
// public BizTraceAspect bizTracingAop() {
// return new BizTraceAspect(tracer());
// }
//
// @Bean
// public Tracer tracer() {
// // 创建 SkywalkingTracer 对象
// SkywalkingTracer tracer = new SkywalkingTracer();
// // 设置为 GlobalTracer 的追踪器
// GlobalTracer.registerIfAbsent(tracer);
// return tracer;
// }
/**
* 创建 TraceFilter 过滤器响应 header 设置 traceId

View File

@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.mybatis.config;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.mybatis.core.handler.DefaultDBFieldHandler;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
@ -46,6 +47,8 @@ public class YudaoMybatisAutoConfiguration {
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor()); // 分页插件
// 按需开启可能会影响到 updateBatch 的地方例如说文件配置管理
// mybatisPlusInterceptor.addInnerInterceptor(new BlockAttackInnerInterceptor()); // 拦截没有指定条件的 update delete 语句
return mybatisPlusInterceptor;
}
@ -80,7 +83,11 @@ public class YudaoMybatisAutoConfiguration {
@Bean
public JacksonTypeHandler jacksonTypeHandler(List<ObjectMapper> objectMappers) {
// 特殊设置 JacksonTypeHandler ObjectMapper
JacksonTypeHandler.setObjectMapper(CollUtil.getFirst(objectMappers));
ObjectMapper objectMapper = CollUtil.getFirst(objectMappers);
if (objectMapper == null) {
objectMapper = JsonUtils.getObjectMapper();
}
JacksonTypeHandler.setObjectMapper(objectMapper);
return new JacksonTypeHandler(Object.class);
}

View File

@ -6,7 +6,6 @@ import com.baomidou.mybatisplus.annotation.TableLogic;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fhs.core.trans.vo.TransPojo;
import lombok.Data;
import org.apache.ibatis.type.JdbcType;
import java.io.Serializable;
import java.time.LocalDateTime;
@ -38,14 +37,14 @@ public abstract class BaseDO implements Serializable, TransPojo {
*
* 使用 String 类型的原因是未来可能会存在非数值的情况留好拓展性
*/
@TableField(fill = FieldFill.INSERT, jdbcType = JdbcType.VARCHAR)
@TableField(fill = FieldFill.INSERT)
private String creator;
/**
* 更新者目前使用 SysUser id 编号
*
* 使用 String 类型的原因是未来可能会存在非数值的情况留好拓展性
*/
@TableField(fill = FieldFill.INSERT_UPDATE, jdbcType = JdbcType.VARCHAR)
@TableField(fill = FieldFill.INSERT_UPDATE)
private String updater;
/**
* 是否删除

View File

@ -18,6 +18,7 @@ import java.util.Objects;
public class DefaultDBFieldHandler implements MetaObjectHandler {
@Override
@SuppressWarnings("PatternVariableCanBeUsed")
public void insertFill(MetaObject metaObject) {
if (Objects.nonNull(metaObject) && metaObject.getOriginalObject() instanceof BaseDO) {
BaseDO baseDO = (BaseDO) metaObject.getOriginalObject();

View File

@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.common.pojo.SortingField;
import cn.iocoder.yudao.framework.mybatis.core.enums.DbTypeEnum;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
@ -47,16 +48,36 @@ public class MyBatisUtils {
return page;
}
@SuppressWarnings("PatternVariableCanBeUsed")
public static <T> void addOrder(Wrapper<T> wrapper, Collection<SortingField> sortingFields) {
if (CollUtil.isEmpty(sortingFields)) {
return;
}
QueryWrapper<T> query = (QueryWrapper<T>) wrapper;
for (SortingField sortingField : sortingFields) {
query.orderBy(true,
SortingField.ORDER_ASC.equals(sortingField.getOrder()),
StrUtil.toUnderlineCase(sortingField.getField()));
if (wrapper instanceof QueryWrapper<T>) {
QueryWrapper<T> query = (QueryWrapper<T>) wrapper;
for (SortingField sortingField : sortingFields) {
query.orderBy(true,
SortingField.ORDER_ASC.equals(sortingField.getOrder()),
StrUtil.toUnderlineCase(sortingField.getField()));
}
} else if (wrapper instanceof LambdaQueryWrapper<T>) {
// LambdaQueryWrapper 不直接支持字符串字段排序使用 last 方法拼接 ORDER BY
LambdaQueryWrapper<T> lambdaQuery = (LambdaQueryWrapper<T>) wrapper;
StringBuilder orderBy = new StringBuilder();
for (SortingField sortingField : sortingFields) {
if (StrUtil.isNotEmpty(orderBy)) {
orderBy.append(", ");
}
orderBy.append(StrUtil.toUnderlineCase(sortingField.getField()))
.append(" ")
.append(SortingField.ORDER_ASC.equals(sortingField.getOrder()) ? "ASC" : "DESC");
}
lambdaQuery.last("ORDER BY " + orderBy);
// 另外个思路https://blog.csdn.net/m0_59084856/article/details/138450913
} else {
throw new IllegalArgumentException("Unsupported wrapper type: " + wrapper.getClass().getName());
}
}
/**

View File

@ -165,7 +165,8 @@ public class YudaoWebSecurityConfigurerAdapter {
// 获得有 @PermitAll 注解的接口
for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : handlerMethodMap.entrySet()) {
HandlerMethod handlerMethod = entry.getValue();
if (!handlerMethod.hasMethodAnnotation(PermitAll.class)) {
if (!handlerMethod.hasMethodAnnotation(PermitAll.class) // 方法级
&& !handlerMethod.getBeanType().isAnnotationPresent(PermitAll.class)) { // 接口级
continue;
}
Set<String> urls = new HashSet<>();

View File

@ -39,12 +39,12 @@
</dependency>
<dependency>
<groupId>com.github.xingfudeshi</groupId>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-api</artifactId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
</dependency>
<dependency>

View File

@ -23,6 +23,7 @@ import org.springframework.http.HttpMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.util.ServletRequestPathUtils;
import java.io.IOException;
@ -128,14 +129,22 @@ public class ApiEncryptFilter extends ApiRequestFilter {
*
* @param request 请求
*/
@SuppressWarnings("PatternVariableCanBeUsed")
private ApiEncrypt getApiEncrypt(HttpServletRequest request) {
try {
// 特殊兼容 SpringBoot 2.X 版本会报错的问题 https://t.zsxq.com/kqyiB
if (!ServletRequestPathUtils.hasParsedRequestPath(request)) {
ServletRequestPathUtils.parseAndCache(request);
}
// 解析 @ApiEncrypt 注解
HandlerExecutionChain mappingHandler = requestMappingHandlerMapping.getHandler(request);
if (mappingHandler == null) {
return null;
}
Object handler = mappingHandler.getHandler();
if (handler instanceof HandlerMethod handlerMethod) {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
ApiEncrypt annotation = handlerMethod.getMethodAnnotation(ApiEncrypt.class);
if (annotation == null) {
annotation = handlerMethod.getBeanType().getAnnotation(ApiEncrypt.class);

View File

@ -1,10 +1,10 @@
package cn.iocoder.yudao.framework.jackson.config;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.common.util.json.databind.NumberSerializer;
import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeDeserializer;
import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeSerializer;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
@ -13,39 +13,65 @@ import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.context.annotation.Bean;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
@AutoConfiguration
@AutoConfiguration(after = JacksonAutoConfiguration.class)
@Slf4j
public class YudaoJacksonAutoConfiguration {
/**
* Builder 源头定制关键使用 *ByType避免 handledType 要求
*/
@Bean
public Jackson2ObjectMapperBuilderCustomizer ldtEpochMillisCustomizer() {
return builder -> builder
// Long -> Number
.serializerByType(Long.class, NumberSerializer.INSTANCE)
.serializerByType(Long.TYPE, NumberSerializer.INSTANCE)
// LocalDate / LocalTime
.serializerByType(LocalDate.class, LocalDateSerializer.INSTANCE)
.deserializerByType(LocalDate.class, LocalDateDeserializer.INSTANCE)
.serializerByType(LocalTime.class, LocalTimeSerializer.INSTANCE)
.deserializerByType(LocalTime.class, LocalTimeDeserializer.INSTANCE)
// LocalDateTime < - > EpochMillis
.serializerByType(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE)
.deserializerByType(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE);
}
/**
* Bean 形式暴露 ModuleBoot 会自动注册到所有 ObjectMapper
*/
@Bean
public Module timestampSupportModuleBean() {
SimpleModule m = new SimpleModule("TimestampSupportModule");
// Long -> Number避免前端精度丢失
m.addSerializer(Long.class, NumberSerializer.INSTANCE);
m.addSerializer(Long.TYPE, NumberSerializer.INSTANCE);
// LocalDate / LocalTime
m.addSerializer(LocalDate.class, LocalDateSerializer.INSTANCE);
m.addDeserializer(LocalDate.class, LocalDateDeserializer.INSTANCE);
m.addSerializer(LocalTime.class, LocalTimeSerializer.INSTANCE);
m.addDeserializer(LocalTime.class, LocalTimeDeserializer.INSTANCE);
// LocalDateTime < - > EpochMillis
m.addSerializer(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE);
m.addDeserializer(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE);
return m;
}
/**
* 初始化全局 JsonUtils直接使用主 ObjectMapper
*/
@Bean
@SuppressWarnings("InstantiationOfUtilityClass")
public JsonUtils jsonUtils(List<ObjectMapper> objectMappers) {
// 1.1 创建 SimpleModule 对象
SimpleModule simpleModule = new SimpleModule();
simpleModule
// 新增 Long 类型序列化规则数值超过 2^53-1 JS 会出现精度丢失问题因此 Long 自动序列化为字符串类型
.addSerializer(Long.class, NumberSerializer.INSTANCE)
.addSerializer(Long.TYPE, NumberSerializer.INSTANCE)
.addSerializer(LocalDate.class, LocalDateSerializer.INSTANCE)
.addDeserializer(LocalDate.class, LocalDateDeserializer.INSTANCE)
.addSerializer(LocalTime.class, LocalTimeSerializer.INSTANCE)
.addDeserializer(LocalTime.class, LocalTimeDeserializer.INSTANCE)
// 新增 LocalDateTime 序列化反序列化规则使用 Long 时间戳
.addSerializer(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE)
.addDeserializer(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE);
// 1.2 注册到 objectMapper
objectMappers.forEach(objectMapper -> objectMapper.registerModule(simpleModule));
// 2. 设置 objectMapper JsonUtils
JsonUtils.init(CollUtil.getFirst(objectMappers));
log.info("[init][初始化 JsonUtils 成功]");
public JsonUtils jsonUtils(ObjectMapper objectMapper) {
JsonUtils.init(objectMapper);
log.debug("[init][初始化 JsonUtils 成功]");
return new JsonUtils();
}

View File

@ -0,0 +1,146 @@
package cn.iocoder.yudao.framework.swagger.config;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import com.github.xiaoymin.knife4j.core.conf.ExtensionsConstants;
import com.github.xiaoymin.knife4j.core.conf.GlobalConstants;
import com.github.xiaoymin.knife4j.spring.configuration.Knife4jProperties;
import com.github.xiaoymin.knife4j.spring.configuration.Knife4jSetting;
import com.github.xiaoymin.knife4j.spring.extension.OpenApiExtensionResolver;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.models.OpenAPI;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.springdoc.core.customizers.GlobalOpenApiCustomizer;
import org.springdoc.core.properties.SpringDocConfigProperties;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RestController;
import java.lang.annotation.Annotation;
import java.util.*;
import java.util.stream.Collectors;
/**
* 增强扩展属性支持
*
* 参考 <a href="https://github.com/xiaoymin/knife4j/issues/913">Spring Boot 3.4 以上版本 /v3/api-docs 解决接口报错依赖修复</a>
*
* @since 4.1.0
* @author <a href="xiaoymin@foxmail.com">xiaoymin@foxmail.com</a>
* 2022/12/11 22:40
*/
@Primary
@Configuration
@Slf4j
public class Knife4jOpenApiCustomizer extends com.github.xiaoymin.knife4j.spring.extension.Knife4jOpenApiCustomizer
implements GlobalOpenApiCustomizer {
final Knife4jProperties knife4jProperties;
final SpringDocConfigProperties properties;
public Knife4jOpenApiCustomizer(Knife4jProperties knife4jProperties, SpringDocConfigProperties properties) {
super(knife4jProperties,properties);
this.knife4jProperties = knife4jProperties;
this.properties = properties;
}
@Override
public void customise(OpenAPI openApi) {
if (knife4jProperties.isEnable()) {
Knife4jSetting setting = knife4jProperties.getSetting();
OpenApiExtensionResolver openApiExtensionResolver = new OpenApiExtensionResolver(setting, knife4jProperties.getDocuments());
// 解析初始化
openApiExtensionResolver.start();
Map<String, Object> objectMap = new HashMap<>();
objectMap.put(GlobalConstants.EXTENSION_OPEN_SETTING_NAME, setting);
objectMap.put(GlobalConstants.EXTENSION_OPEN_MARKDOWN_NAME, openApiExtensionResolver.getMarkdownFiles());
openApi.addExtension(GlobalConstants.EXTENSION_OPEN_API_NAME, objectMap);
addOrderExtension(openApi);
}
}
/**
* OpenAPI tags 字段添加 x-order 属性
*
* @param openApi openApi
*/
private void addOrderExtension(OpenAPI openApi) {
if (CollectionUtils.isEmpty(properties.getGroupConfigs())) {
return;
}
// 获取包扫描路径
Set<String> packagesToScan =
properties.getGroupConfigs().stream()
.map(SpringDocConfigProperties.GroupConfig::getPackagesToScan)
.filter(toScan -> !CollectionUtils.isEmpty(toScan))
.flatMap(List::stream)
.collect(Collectors.toSet());
if (CollectionUtils.isEmpty(packagesToScan)) {
return;
}
// 扫描包下被 ApiSupport 注解的 RestController Class
Set<Class<?>> classes = packagesToScan.stream()
.map(packageToScan -> scanPackageByAnnotation(packageToScan, RestController.class))
.flatMap(Set::stream)
.filter(clazz -> clazz.isAnnotationPresent(ApiSupport.class))
.collect(Collectors.toSet());
if (!CollectionUtils.isEmpty(classes)) {
// ApiSupport oder 值存入 tagSortMap<Tag.name,ApiSupport.order>
Map<String, Integer> tagOrderMap = new HashMap<>();
classes.forEach(clazz -> {
Tag tag = getTag(clazz);
if (Objects.nonNull(tag)) {
ApiSupport apiSupport = clazz.getAnnotation(ApiSupport.class);
tagOrderMap.putIfAbsent(tag.name(), apiSupport.order());
}
});
// openApi tags 字段添加 x-order 增强属性
if (openApi.getTags() != null) {
openApi.getTags().forEach(tag -> {
if (tagOrderMap.containsKey(tag.getName())) {
tag.addExtension(ExtensionsConstants.EXTENSION_ORDER, tagOrderMap.get(tag.getName()));
}
});
}
}
}
private Tag getTag(Class<?> clazz) {
// 从类上获取
Tag tag = clazz.getAnnotation(Tag.class);
if (Objects.isNull(tag)) {
// 从接口上获取
Class<?>[] interfaces = clazz.getInterfaces();
if (ArrayUtils.isNotEmpty(interfaces)) {
for (Class<?> interfaceClazz : interfaces) {
Tag anno = interfaceClazz.getAnnotation(Tag.class);
if (Objects.nonNull(anno)) {
tag = anno;
break;
}
}
}
}
return tag;
}
private Set<Class<?>> scanPackageByAnnotation(String packageName, final Class<? extends Annotation> annotationClass) {
ClassPathScanningCandidateComponentProvider scanner =
new ClassPathScanningCandidateComponentProvider(false);
scanner.addIncludeFilter(new AnnotationTypeFilter(annotationClass));
Set<Class<?>> classes = new HashSet<>();
for (BeanDefinition beanDefinition : scanner.findCandidateComponents(packageName)) {
try {
Class<?> clazz = Class.forName(beanDefinition.getBeanClassName());
classes.add(clazz);
} catch (ClassNotFoundException ignore) {
}
}
return classes;
}
}

View File

@ -23,6 +23,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Primary;
import org.springframework.http.HttpHeaders;
@ -46,6 +47,7 @@ import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_
@ConditionalOnClass({OpenAPI.class})
@EnableConfigurationProperties(SwaggerProperties.class)
@ConditionalOnProperty(prefix = "springdoc.api-docs", name = "enabled", havingValue = "true", matchIfMissing = true) // 设置为 false 禁用
@Import(Knife4jOpenApiCustomizer.class)
public class YudaoSwaggerAutoConfiguration {
// ========== 全局 OpenAPI 配置 ==========

View File

@ -36,6 +36,7 @@ import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.resource.NoResourceFoundException;
@ -93,6 +94,9 @@ public class GlobalExceptionHandler {
if (ex instanceof ValidationException) {
return validationException((ValidationException) ex);
}
if (ex instanceof MaxUploadSizeExceededException) {
return maxUploadSizeExceededExceptionHandler((MaxUploadSizeExceededException) ex);
}
if (ex instanceof NoHandlerFoundException) {
return noHandlerFoundExceptionHandler((NoHandlerFoundException) ex);
}
@ -111,9 +115,6 @@ public class GlobalExceptionHandler {
if (ex instanceof AccessDeniedException) {
return accessDeniedExceptionHandler(request, (AccessDeniedException) ex);
}
if (ex instanceof UncheckedExecutionException && ex.getCause() != ex) {
return allExceptionHandler(request, ex.getCause());
}
return defaultExceptionHandler(request, ex);
}
@ -181,6 +182,7 @@ public class GlobalExceptionHandler {
* 例如说接口上设置了 @RequestBody 实体中 xx 属性类型为 Integer结果传递 xx 参数类型为 String
*/
@ExceptionHandler(HttpMessageNotReadableException.class)
@SuppressWarnings("PatternVariableCanBeUsed")
public CommonResult<?> methodArgumentTypeInvalidFormatExceptionHandler(HttpMessageNotReadableException ex) {
log.warn("[methodArgumentTypeInvalidFormatExceptionHandler]", ex);
if (ex.getCause() instanceof InvalidFormatException) {
@ -213,6 +215,14 @@ public class GlobalExceptionHandler {
return CommonResult.error(BAD_REQUEST);
}
/**
* 处理上传文件过大异常
*/
@ExceptionHandler(MaxUploadSizeExceededException.class)
public CommonResult<?> maxUploadSizeExceededExceptionHandler(MaxUploadSizeExceededException ex) {
return CommonResult.error(BAD_REQUEST.getCode(), "上传文件过大,请调整后重试");
}
/**
* 处理 SpringMVC 请求地址不存在
*
@ -309,6 +319,12 @@ public class GlobalExceptionHandler {
*/
@ExceptionHandler(value = Exception.class)
public CommonResult<?> defaultExceptionHandler(HttpServletRequest req, Throwable ex) {
// 特殊如果是 ServiceException 的异常则直接返回
// 例如说https://gitee.com/zhijiantianya/yudao-cloud/issues/ICSSRMhttps://gitee.com/zhijiantianya/yudao-cloud/issues/ICT6FM
if (ex.getCause() != null && ex.getCause() instanceof ServiceException) {
return serviceExceptionHandler((ServiceException) ex.getCause());
}
// 情况一处理表不存在的异常
CommonResult<?> tableNotExistsResult = handleTableNotExists(ex);
if (tableNotExistsResult != null) {

View File

@ -144,6 +144,7 @@ public class WebFrameworkUtils {
return (CommonResult<?>) request.getAttribute(REQUEST_ATTRIBUTE_COMMON_RESULT);
}
@SuppressWarnings("PatternVariableCanBeUsed")
public static HttpServletRequest getRequest() {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (!(requestAttributes instanceof ServletRequestAttributes)) {

View File

@ -19,8 +19,8 @@
国外OpenAI、Ollama、Midjourney、StableDiffusion、Suno
</description>
<properties>
<spring-ai.version>1.0.0</spring-ai.version>
<alibaba-ai.version>1.0.0.2</alibaba-ai.version>
<spring-ai.version>1.0.1</spring-ai.version>
<alibaba-ai.version>1.0.0.3</alibaba-ai.version>
<tinyflow.version>1.0.2</tinyflow.version>
</properties>
@ -84,6 +84,11 @@
<artifactId>spring-ai-starter-model-azure-openai</artifactId>
<version>${spring-ai.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-anthropic</artifactId>
<version>${spring-ai.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-deepseek</artifactId>
@ -182,6 +187,24 @@
</exclusions>
</dependency>
<!-- MCP 相关 -->
<!--
特殊说明:不能使用 spring-ai-starter-mcp-server-webflux 或 spring-ai-starter-mcp-client-webflux
原因:项目使用了 SpringMVC而不是 WebFlux。引入上述 2 个,会导致 SSE Server 失效。
-->
<dependency>
<!-- 服务端 -->
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
<version>${spring-ai.version}</version>
</dependency>
<dependency>
<!-- 客户端 -->
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-client</artifactId>
<version>${spring-ai.version}</version>
</dependency>
<!-- TinyFlowAI 工作流 -->
<dependency>
<groupId>dev.tinyflow</groupId>

View File

@ -20,9 +20,46 @@ tenant-id: {{adminTenantId}}
"content": "1+1=?"
}
### 获得指定对话的消息列表
GET {{baseUrl}}/ai/chat/message/list-by-conversation-id?conversationId=1781604279872581649
### 发送消息(流式)【带文件】
POST {{baseUrl}}/ai/chat/message/send-stream
Content-Type: application/json
Authorization: {{token}}
tenant-id: {{adminTenantId}}
{
"conversationId": "1781604279872581797",
"content": "图片里有什么?",
"attachmentUrls": ["http://test.yudao.iocoder.cn/1755531278.jpeg"]
}
### 发送消息(流式)【追问带文件】
POST {{baseUrl}}/ai/chat/message/send-stream
Content-Type: application/json
Authorization: {{token}}
tenant-id: {{adminTenantId}}
{
"conversationId": "1781604279872581799",
"content": "说下图片里,有哪些字?",
"useContext": true
}
### 发送消息(流式)【联网搜索】
POST {{baseUrl}}/ai/chat/message/send-stream
Content-Type: application/json
Authorization: {{token}}
tenant-id: {{adminTenantId}}
{
"conversationId": "1781604279872581799",
"content": "今天是周几?",
"useSearch": true
}
### 获得指定对话的消息列表
GET {{baseUrl}}/ai/chat/message/list-by-conversation-id?conversationId=1781604279872581799
Authorization: {{token}}
tenant-id: {{adminTenantId}}
### 删除消息
DELETE {{baseUrl}}/ai/chat/message/delete?id=50

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message;
import cn.iocoder.yudao.module.ai.framework.ai.core.webserch.AiWebSearchResponse;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@ -37,6 +38,9 @@ public class AiChatMessageRespVO {
@Schema(description = "聊天内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "你好,你好啊")
private String content;
@Schema(description = "推理内容", example = "要达到这个目标,你需要...")
private String reasoningContent;
@Schema(description = "是否携带上下文", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
private Boolean useContext;
@ -46,6 +50,12 @@ public class AiChatMessageRespVO {
@Schema(description = "知识库段落数组")
private List<KnowledgeSegment> segments;
@Schema(description = "联网搜索的网页内容数组")
private List<AiWebSearchResponse.WebPage> webSearchPages;
@Schema(description = "附件 URL 数组", example = "https://www.iocoder.cn/1.png")
private List<String> attachmentUrls;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-05-12 12:51")
private LocalDateTime createTime;

View File

@ -3,9 +3,9 @@ package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
@Schema(description = "管理后台 - AI 聊天消息发送 Request VO")
@Data
@ -22,4 +22,10 @@ public class AiChatMessageSendReqVO {
@Schema(description = "是否携带上下文", example = "true")
private Boolean useContext;
@Schema(description = "是否联网搜索", example = "true")
private Boolean useSearch;
@Schema(description = "附件 URL 数组", example = "https://www.iocoder.cn/1.png")
private List<String> attachmentUrls;
}

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message;
import cn.iocoder.yudao.module.ai.framework.ai.core.webserch.AiWebSearchResponse;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@ -29,12 +30,18 @@ public class AiChatMessageSendRespVO {
@Schema(description = "聊天内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "你好,你好啊")
private String content;
@Schema(description = "推理内容", example = "要达到这个目标,你需要...")
private String reasoningContent;
@Schema(description = "知识库段落编号数组", example = "[1,2,3]")
private List<Long> segmentIds;
@Schema(description = "知识库段落数组")
private List<AiChatMessageRespVO.KnowledgeSegment> segments;
@Schema(description = "联网搜索的网页内容数组")
private List<AiWebSearchResponse.WebPage> webSearchPages;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;

View File

@ -52,6 +52,9 @@ public class AiChatRoleRespVO implements VO {
@Schema(description = "引用的工具编号列表", example = "1,2,3")
private List<Long> toolIds;
@Schema(description = "引用的 MCP Client 名字列表", example = "filesystem")
private List<String> mcpClientNames;
@Schema(description = "是否公开", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Boolean publicStatus;

View File

@ -37,4 +37,7 @@ public class AiChatRoleSaveMyReqVO {
@Schema(description = "引用的工具编号列表", example = "1,2,3")
private List<Long> toolIds;
@Schema(description = "引用的 MCP Client 名字列表", example = "filesystem")
private List<String> mcpClientNames;
}

View File

@ -50,6 +50,9 @@ public class AiChatRoleSaveReqVO {
@Schema(description = "引用的工具编号列表", example = "1,2,3")
private List<Long> toolIds;
@Schema(description = "引用的 MCP Client 名字列表", example = "filesystem")
private List<String> mcpClientNames;
@Schema(description = "是否公开", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "是否公开不能为空")
private Boolean publicStatus;

View File

@ -2,14 +2,20 @@ package cn.iocoder.yudao.module.ai.dal.dataobject.chat;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler;
import cn.iocoder.yudao.framework.mybatis.core.type.StringListTypeHandler;
import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeSegmentDO;
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO;
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiModelDO;
import cn.iocoder.yudao.module.ai.framework.ai.core.webserch.AiWebSearchResponse;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.ai.chat.messages.MessageType;
import java.util.List;
@ -87,6 +93,10 @@ public class AiChatMessageDO extends BaseDO {
* 聊天内容
*/
private String content;
/**
* 推理内容
*/
private String reasoningContent;
/**
* 是否携带上下文
@ -101,4 +111,16 @@ public class AiChatMessageDO extends BaseDO {
@TableField(typeHandler = LongListTypeHandler.class)
private List<Long> segmentIds;
/**
* 联网搜索的网页内容数组
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private List<AiWebSearchResponse.WebPage> webSearchPages;
/**
* 附件 URL 数组
*/
@TableField(typeHandler = StringListTypeHandler.class)
private List<String> attachmentUrls;
}

View File

@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.ai.dal.dataobject.model;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler;
import cn.iocoder.yudao.framework.mybatis.core.type.StringListTypeHandler;
import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
@ -80,6 +81,13 @@ public class AiChatRoleDO extends BaseDO {
*/
@TableField(typeHandler = LongListTypeHandler.class)
private List<Long> toolIds;
/**
* 引用的 MCP Client 名字列表
*
* 关联 spring.ai.mcp.client 下的名字
*/
@TableField(typeHandler = StringListTypeHandler.class)
private List<String> mcpClientNames;
/**
* 是否公开

View File

@ -1,8 +1,8 @@
package cn.iocoder.yudao.module.ai.dal.dataobject.model;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.ai.service.model.tool.DirectoryListToolFunction;
import cn.iocoder.yudao.module.ai.service.model.tool.WeatherQueryToolFunction;
import cn.iocoder.yudao.module.ai.tool.function.DirectoryListToolFunction;
import cn.iocoder.yudao.module.ai.tool.function.WeatherQueryToolFunction;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;

View File

@ -33,6 +33,8 @@ public enum AiPlatformEnum implements ArrayValuable<String> {
OPENAI("OpenAI", "OpenAI"), // OpenAI 官方
AZURE_OPENAI("AzureOpenAI", "AzureOpenAI"), // OpenAI 微软
ANTHROPIC("Anthropic", "Anthropic"), // Anthropic Claude
GEMINI("Gemini", "Gemini"), // 谷歌 Gemini
OLLAMA("Ollama", "Ollama"),
STABLE_DIFFUSION("StableDiffusion", "StableDiffusion"), // Stability AI

View File

@ -2,25 +2,34 @@ package cn.iocoder.yudao.module.ai.framework.ai.config;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.module.ai.framework.ai.core.AiModelFactory;
import cn.iocoder.yudao.module.ai.framework.ai.core.AiModelFactoryImpl;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.AiModelFactory;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.AiModelFactoryImpl;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.baichuan.BaiChuanChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.doubao.DouBaoChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.gemini.GeminiChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.hunyuan.HunYuanChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.midjourney.api.MidjourneyApi;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowApiConstants;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.suno.api.SunoApi;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.xinghuo.XingHuoChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.webserch.AiWebSearchClient;
import cn.iocoder.yudao.module.ai.framework.ai.core.webserch.bocha.AiBoChaWebSearchClient;
import cn.iocoder.yudao.module.ai.tool.method.PersonService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.deepseek.DeepSeekChatModel;
import org.springframework.ai.deepseek.DeepSeekChatOptions;
import org.springframework.ai.deepseek.api.DeepSeekApi;
import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.model.tool.ToolCallingManager;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.support.ToolCallbacks;
import org.springframework.ai.tokenizer.JTokkitTokenCountEstimator;
import org.springframework.ai.tokenizer.TokenCountEstimator;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.vectorstore.milvus.autoconfigure.MilvusServiceClientProperties;
import org.springframework.ai.vectorstore.milvus.autoconfigure.MilvusVectorStoreProperties;
import org.springframework.ai.vectorstore.qdrant.autoconfigure.QdrantVectorStoreProperties;
@ -30,6 +39,8 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
/**
* 芋道 AI 自动配置
*
@ -51,20 +62,49 @@ public class AiAutoConfiguration {
// ========== 各种 AI Client 创建 ==========
@Bean
@ConditionalOnProperty(value = "yudao.ai.gemini.enable", havingValue = "true")
public GeminiChatModel geminiChatModel(YudaoAiProperties yudaoAiProperties) {
YudaoAiProperties.Gemini properties = yudaoAiProperties.getGemini();
return buildGeminiChatClient(properties);
}
public GeminiChatModel buildGeminiChatClient(YudaoAiProperties.Gemini properties) {
if (StrUtil.isEmpty(properties.getModel())) {
properties.setModel(GeminiChatModel.MODEL_DEFAULT);
}
OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
.openAiApi(OpenAiApi.builder()
.baseUrl(GeminiChatModel.BASE_URL)
.completionsPath(GeminiChatModel.COMPLETE_PATH)
.apiKey(properties.getApiKey())
.build())
.defaultOptions(OpenAiChatOptions.builder()
.model(properties.getModel())
.temperature(properties.getTemperature())
.maxTokens(properties.getMaxTokens())
.topP(properties.getTopP())
.build())
.toolCallingManager(getToolCallingManager())
.build();
return new GeminiChatModel(openAiChatModel);
}
@Bean
@ConditionalOnProperty(value = "yudao.ai.doubao.enable", havingValue = "true")
public DouBaoChatModel douBaoChatClient(YudaoAiProperties yudaoAiProperties) {
YudaoAiProperties.DouBaoProperties properties = yudaoAiProperties.getDoubao();
YudaoAiProperties.DouBao properties = yudaoAiProperties.getDoubao();
return buildDouBaoChatClient(properties);
}
public DouBaoChatModel buildDouBaoChatClient(YudaoAiProperties.DouBaoProperties properties) {
public DouBaoChatModel buildDouBaoChatClient(YudaoAiProperties.DouBao properties) {
if (StrUtil.isEmpty(properties.getModel())) {
properties.setModel(DouBaoChatModel.MODEL_DEFAULT);
}
OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
.openAiApi(OpenAiApi.builder()
.baseUrl(DouBaoChatModel.BASE_URL)
.completionsPath(DouBaoChatModel.COMPLETE_PATH)
.apiKey(properties.getApiKey())
.build())
.defaultOptions(OpenAiChatOptions.builder()
@ -81,20 +121,20 @@ public class AiAutoConfiguration {
@Bean
@ConditionalOnProperty(value = "yudao.ai.siliconflow.enable", havingValue = "true")
public SiliconFlowChatModel siliconFlowChatClient(YudaoAiProperties yudaoAiProperties) {
YudaoAiProperties.SiliconFlowProperties properties = yudaoAiProperties.getSiliconflow();
YudaoAiProperties.SiliconFlow properties = yudaoAiProperties.getSiliconflow();
return buildSiliconFlowChatClient(properties);
}
public SiliconFlowChatModel buildSiliconFlowChatClient(YudaoAiProperties.SiliconFlowProperties properties) {
public SiliconFlowChatModel buildSiliconFlowChatClient(YudaoAiProperties.SiliconFlow properties) {
if (StrUtil.isEmpty(properties.getModel())) {
properties.setModel(SiliconFlowApiConstants.MODEL_DEFAULT);
}
OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
.openAiApi(OpenAiApi.builder()
DeepSeekChatModel openAiChatModel = DeepSeekChatModel.builder()
.deepSeekApi(DeepSeekApi.builder()
.baseUrl(SiliconFlowApiConstants.DEFAULT_BASE_URL)
.apiKey(properties.getApiKey())
.build())
.defaultOptions(OpenAiChatOptions.builder()
.defaultOptions(DeepSeekChatOptions.builder()
.model(properties.getModel())
.temperature(properties.getTemperature())
.maxTokens(properties.getMaxTokens())
@ -108,11 +148,11 @@ public class AiAutoConfiguration {
@Bean
@ConditionalOnProperty(value = "yudao.ai.hunyuan.enable", havingValue = "true")
public HunYuanChatModel hunYuanChatClient(YudaoAiProperties yudaoAiProperties) {
YudaoAiProperties.HunYuanProperties properties = yudaoAiProperties.getHunyuan();
YudaoAiProperties.HunYuan properties = yudaoAiProperties.getHunyuan();
return buildHunYuanChatClient(properties);
}
public HunYuanChatModel buildHunYuanChatClient(YudaoAiProperties.HunYuanProperties properties) {
public HunYuanChatModel buildHunYuanChatClient(YudaoAiProperties.HunYuan properties) {
if (StrUtil.isEmpty(properties.getModel())) {
properties.setModel(HunYuanChatModel.MODEL_DEFAULT);
}
@ -122,13 +162,14 @@ public class AiAutoConfiguration {
StrUtil.startWithIgnoreCase(properties.getModel(), "deepseek") ? HunYuanChatModel.DEEP_SEEK_BASE_URL
: HunYuanChatModel.BASE_URL);
}
// 创建 OpenAiChatModelHunYuanChatModel 对象
OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
.openAiApi(OpenAiApi.builder()
// 创建 DeepSeekChatModelHunYuanChatModel 对象
DeepSeekChatModel openAiChatModel = DeepSeekChatModel.builder()
.deepSeekApi(DeepSeekApi.builder()
.baseUrl(properties.getBaseUrl())
.completionsPath(HunYuanChatModel.COMPLETE_PATH)
.apiKey(properties.getApiKey())
.build())
.defaultOptions(OpenAiChatOptions.builder()
.defaultOptions(DeepSeekChatOptions.builder()
.model(properties.getModel())
.temperature(properties.getTemperature())
.maxTokens(properties.getMaxTokens())
@ -142,25 +183,30 @@ public class AiAutoConfiguration {
@Bean
@ConditionalOnProperty(value = "yudao.ai.xinghuo.enable", havingValue = "true")
public XingHuoChatModel xingHuoChatClient(YudaoAiProperties yudaoAiProperties) {
YudaoAiProperties.XingHuoProperties properties = yudaoAiProperties.getXinghuo();
YudaoAiProperties.XingHuo properties = yudaoAiProperties.getXinghuo();
return buildXingHuoChatClient(properties);
}
public XingHuoChatModel buildXingHuoChatClient(YudaoAiProperties.XingHuoProperties properties) {
public XingHuoChatModel buildXingHuoChatClient(YudaoAiProperties.XingHuo properties) {
if (StrUtil.isEmpty(properties.getModel())) {
properties.setModel(XingHuoChatModel.MODEL_DEFAULT);
}
OpenAiApi.Builder builder = OpenAiApi.builder()
.baseUrl(XingHuoChatModel.BASE_URL_V1)
.apiKey(properties.getAppKey() + ":" + properties.getSecretKey());
if ("x1".equals(properties.getModel())) {
builder.baseUrl(XingHuoChatModel.BASE_URL_V2)
.completionsPath(XingHuoChatModel.BASE_COMPLETIONS_PATH_V2);
}
OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
.openAiApi(OpenAiApi.builder()
.baseUrl(XingHuoChatModel.BASE_URL)
.apiKey(properties.getAppKey() + ":" + properties.getSecretKey())
.build())
.openAiApi(builder.build())
.defaultOptions(OpenAiChatOptions.builder()
.model(properties.getModel())
.temperature(properties.getTemperature())
.maxTokens(properties.getMaxTokens())
.topP(properties.getTopP())
.build())
// TODO @芋艿星火的 function call bug会报 ToolResponseMessage must have an id 错误
.toolCallingManager(getToolCallingManager())
.build();
return new XingHuoChatModel(openAiChatModel);
@ -169,11 +215,11 @@ public class AiAutoConfiguration {
@Bean
@ConditionalOnProperty(value = "yudao.ai.baichuan.enable", havingValue = "true")
public BaiChuanChatModel baiChuanChatClient(YudaoAiProperties yudaoAiProperties) {
YudaoAiProperties.BaiChuanProperties properties = yudaoAiProperties.getBaichuan();
YudaoAiProperties.BaiChuan properties = yudaoAiProperties.getBaichuan();
return buildBaiChuanChatClient(properties);
}
public BaiChuanChatModel buildBaiChuanChatClient(YudaoAiProperties.BaiChuanProperties properties) {
public BaiChuanChatModel buildBaiChuanChatClient(YudaoAiProperties.BaiChuan properties) {
if (StrUtil.isEmpty(properties.getModel())) {
properties.setModel(BaiChuanChatModel.MODEL_DEFAULT);
}
@ -196,7 +242,7 @@ public class AiAutoConfiguration {
@Bean
@ConditionalOnProperty(value = "yudao.ai.midjourney.enable", havingValue = "true")
public MidjourneyApi midjourneyApi(YudaoAiProperties yudaoAiProperties) {
YudaoAiProperties.MidjourneyProperties config = yudaoAiProperties.getMidjourney();
YudaoAiProperties.Midjourney config = yudaoAiProperties.getMidjourney();
return new MidjourneyApi(config.getBaseUrl(), config.getApiKey(), config.getNotifyUrl());
}
@ -222,4 +268,22 @@ public class AiAutoConfiguration {
return SpringUtil.getBean(ToolCallingManager.class);
}
// ========== Web Search 相关 ==========
@Bean
@ConditionalOnProperty(value = "yudao.ai.web-search.enable", havingValue = "true")
public AiWebSearchClient webSearchClient(YudaoAiProperties yudaoAiProperties) {
return new AiBoChaWebSearchClient(yudaoAiProperties.getWebSearch().getApiKey());
}
// ========== MCP 相关 ==========
/**
* 参考自 <a href="https://docs.spring.io/spring-ai/reference/api/mcp/mcp-client-boot-starter-docs.html">MCP Server Boot Starter</>
*/
@Bean
public List<ToolCallback> toolCallbacks(PersonService personService) {
return List.of(ToolCallbacks.from(personService));
}
}

View File

@ -13,49 +13,54 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
@Data
public class YudaoAiProperties {
/**
* 谷歌 Gemini
*/
private Gemini gemini;
/**
* 字节豆包
*/
@SuppressWarnings("SpellCheckingInspection")
private DouBaoProperties doubao;
private DouBao doubao;
/**
* 腾讯混元
*/
@SuppressWarnings("SpellCheckingInspection")
private HunYuanProperties hunyuan;
private HunYuan hunyuan;
/**
* 硅基流动
*/
@SuppressWarnings("SpellCheckingInspection")
private SiliconFlowProperties siliconflow;
private SiliconFlow siliconflow;
/**
* 讯飞星火
*/
@SuppressWarnings("SpellCheckingInspection")
private XingHuoProperties xinghuo;
private XingHuo xinghuo;
/**
* 百川
*/
@SuppressWarnings("SpellCheckingInspection")
private BaiChuanProperties baichuan;
private BaiChuan baichuan;
/**
* Midjourney 绘图
*/
private MidjourneyProperties midjourney;
private Midjourney midjourney;
/**
* Suno 音乐
*/
@SuppressWarnings("SpellCheckingInspection")
private SunoProperties suno;
private Suno suno;
/**
* 网络搜索
*/
private WebSearch webSearch;
@Data
public static class DouBaoProperties {
public static class Gemini {
private String enable;
private String apiKey;
@ -68,7 +73,20 @@ public class YudaoAiProperties {
}
@Data
public static class HunYuanProperties {
public static class DouBao {
private String enable;
private String apiKey;
private String model;
private Double temperature;
private Integer maxTokens;
private Double topP;
}
@Data
public static class HunYuan {
private String enable;
private String baseUrl;
@ -82,7 +100,7 @@ public class YudaoAiProperties {
}
@Data
public static class SiliconFlowProperties {
public static class SiliconFlow {
private String enable;
private String apiKey;
@ -95,7 +113,7 @@ public class YudaoAiProperties {
}
@Data
public static class XingHuoProperties {
public static class XingHuo {
private String enable;
private String appId;
@ -110,7 +128,7 @@ public class YudaoAiProperties {
}
@Data
public static class BaiChuanProperties {
public static class BaiChuan {
private String enable;
private String apiKey;
@ -123,7 +141,7 @@ public class YudaoAiProperties {
}
@Data
public static class MidjourneyProperties {
public static class Midjourney {
private String enable;
private String baseUrl;
@ -134,12 +152,21 @@ public class YudaoAiProperties {
}
@Data
public static class SunoProperties {
public static class Suno {
private boolean enable = false;
private boolean enable;
private String baseUrl;
}
@Data
public static class WebSearch {
private boolean enable;
private String apiKey;
}
}

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.ai.framework.ai.core;
package cn.iocoder.yudao.module.ai.framework.ai.core.model;
import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.midjourney.api.MidjourneyApi;

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.ai.framework.ai.core;
package cn.iocoder.yudao.module.ai.framework.ai.core.model;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Assert;
@ -14,6 +14,7 @@ import cn.iocoder.yudao.module.ai.framework.ai.config.AiAutoConfiguration;
import cn.iocoder.yudao.module.ai.framework.ai.config.YudaoAiProperties;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.baichuan.BaiChuanChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.doubao.DouBaoChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.gemini.GeminiChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.hunyuan.HunYuanChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.midjourney.api.MidjourneyApi;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowApiConstants;
@ -67,6 +68,7 @@ import org.springframework.ai.minimax.MiniMaxChatOptions;
import org.springframework.ai.minimax.MiniMaxEmbeddingModel;
import org.springframework.ai.minimax.MiniMaxEmbeddingOptions;
import org.springframework.ai.minimax.api.MiniMaxApi;
import org.springframework.ai.model.anthropic.autoconfigure.AnthropicChatAutoConfiguration;
import org.springframework.ai.model.azure.openai.autoconfigure.AzureOpenAiChatAutoConfiguration;
import org.springframework.ai.model.azure.openai.autoconfigure.AzureOpenAiEmbeddingAutoConfiguration;
import org.springframework.ai.model.azure.openai.autoconfigure.AzureOpenAiEmbeddingProperties;
@ -93,6 +95,8 @@ import org.springframework.ai.openai.OpenAiImageModel;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.openai.api.OpenAiImageApi;
import org.springframework.ai.openai.api.common.OpenAiApiConstants;
import org.springframework.ai.anthropic.AnthropicChatModel;
import org.springframework.ai.anthropic.api.AnthropicApi;
import org.springframework.ai.stabilityai.StabilityAiImageModel;
import org.springframework.ai.stabilityai.api.StabilityAiApi;
import org.springframework.ai.vectorstore.SimpleVectorStore;
@ -168,6 +172,10 @@ public class AiModelFactoryImpl implements AiModelFactory {
return buildOpenAiChatModel(apiKey, url);
case AZURE_OPENAI:
return buildAzureOpenAiChatModel(apiKey, url);
case ANTHROPIC:
return buildAnthropicChatModel(apiKey, url);
case GEMINI:
return buildGeminiChatModel(apiKey);
case OLLAMA:
return buildOllamaChatModel(url);
default:
@ -206,6 +214,10 @@ public class AiModelFactoryImpl implements AiModelFactory {
return SpringUtil.getBean(OpenAiChatModel.class);
case AZURE_OPENAI:
return SpringUtil.getBean(AzureOpenAiChatModel.class);
case ANTHROPIC:
return SpringUtil.getBean(AnthropicChatModel.class);
case GEMINI:
return SpringUtil.getBean(GeminiChatModel.class);
case OLLAMA:
return SpringUtil.getBean(OllamaChatModel.class);
default:
@ -260,7 +272,7 @@ public class AiModelFactoryImpl implements AiModelFactory {
String cacheKey = buildClientCacheKey(MidjourneyApi.class, AiPlatformEnum.MIDJOURNEY.getPlatform(), apiKey,
url);
return Singleton.get(cacheKey, (Func0<MidjourneyApi>) () -> {
YudaoAiProperties.MidjourneyProperties properties = SpringUtil.getBean(YudaoAiProperties.class)
YudaoAiProperties.Midjourney properties = SpringUtil.getBean(YudaoAiProperties.class)
.getMidjourney();
return new MidjourneyApi(url, apiKey, properties.getNotifyUrl());
});
@ -347,7 +359,7 @@ public class AiModelFactoryImpl implements AiModelFactory {
* 可参考 {@link DashScopeImageAutoConfiguration} dashScopeImageModel 方法
*/
private static DashScopeImageModel buildTongYiImagesModel(String key) {
DashScopeImageApi dashScopeImageApi = new DashScopeImageApi(key);
DashScopeImageApi dashScopeImageApi = DashScopeImageApi.builder().apiKey(key).build();
return DashScopeImageModel.builder()
.dashScopeApi(dashScopeImageApi)
.build();
@ -397,7 +409,7 @@ public class AiModelFactoryImpl implements AiModelFactory {
* 可参考 {@link AiAutoConfiguration#douBaoChatClient(YudaoAiProperties)}
*/
private ChatModel buildDouBaoChatModel(String apiKey) {
YudaoAiProperties.DouBaoProperties properties = new YudaoAiProperties.DouBaoProperties()
YudaoAiProperties.DouBao properties = new YudaoAiProperties.DouBao()
.setApiKey(apiKey);
return new AiAutoConfiguration().buildDouBaoChatClient(properties);
}
@ -406,7 +418,7 @@ public class AiModelFactoryImpl implements AiModelFactory {
* 可参考 {@link AiAutoConfiguration#hunYuanChatClient(YudaoAiProperties)}
*/
private ChatModel buildHunYuanChatModel(String apiKey, String url) {
YudaoAiProperties.HunYuanProperties properties = new YudaoAiProperties.HunYuanProperties()
YudaoAiProperties.HunYuan properties = new YudaoAiProperties.HunYuan()
.setBaseUrl(url).setApiKey(apiKey);
return new AiAutoConfiguration().buildHunYuanChatClient(properties);
}
@ -415,7 +427,7 @@ public class AiModelFactoryImpl implements AiModelFactory {
* 可参考 {@link AiAutoConfiguration#siliconFlowChatClient(YudaoAiProperties)}
*/
private ChatModel buildSiliconFlowChatModel(String apiKey) {
YudaoAiProperties.SiliconFlowProperties properties = new YudaoAiProperties.SiliconFlowProperties()
YudaoAiProperties.SiliconFlow properties = new YudaoAiProperties.SiliconFlow()
.setApiKey(apiKey);
return new AiAutoConfiguration().buildSiliconFlowChatClient(properties);
}
@ -473,7 +485,7 @@ public class AiModelFactoryImpl implements AiModelFactory {
private static XingHuoChatModel buildXingHuoChatModel(String key) {
List<String> keys = StrUtil.split(key, '|');
Assert.equals(keys.size(), 2, "XingHuoChatClient 的密钥需要 (appKey|secretKey) 格式");
YudaoAiProperties.XingHuoProperties properties = new YudaoAiProperties.XingHuoProperties()
YudaoAiProperties.XingHuo properties = new YudaoAiProperties.XingHuo()
.setAppKey(keys.get(0)).setSecretKey(keys.get(1));
return new AiAutoConfiguration().buildXingHuoChatClient(properties);
}
@ -482,7 +494,7 @@ public class AiModelFactoryImpl implements AiModelFactory {
* 可参考 {@link AiAutoConfiguration#baiChuanChatClient(YudaoAiProperties)}
*/
private BaiChuanChatModel buildBaiChuanChatModel(String apiKey) {
YudaoAiProperties.BaiChuanProperties properties = new YudaoAiProperties.BaiChuanProperties()
YudaoAiProperties.BaiChuan properties = new YudaoAiProperties.BaiChuan()
.setApiKey(apiKey);
return new AiAutoConfiguration().buildBaiChuanChatClient(properties);
}
@ -512,6 +524,30 @@ public class AiModelFactoryImpl implements AiModelFactory {
.build();
}
/**
* 可参考 {@link AnthropicChatAutoConfiguration} anthropicApi 方法
*/
private static AnthropicChatModel buildAnthropicChatModel(String apiKey, String url) {
AnthropicApi.Builder builder = AnthropicApi.builder().apiKey(apiKey);
if (StrUtil.isNotEmpty(url)) {
builder.baseUrl(url);
}
AnthropicApi anthropicApi = builder.build();
return AnthropicChatModel.builder()
.anthropicApi(anthropicApi)
.toolCallingManager(getToolCallingManager())
.build();
}
/**
* 可参考 {@link AiAutoConfiguration#buildGeminiChatClient(YudaoAiProperties.Gemini)}
*/
private static GeminiChatModel buildGeminiChatModel(String apiKey) {
YudaoAiProperties.Gemini properties = SpringUtil.getBean(YudaoAiProperties.class)
.getGemini().setApiKey(apiKey);
return new AiAutoConfiguration().buildGeminiChatClient(properties);
}
/**
* 可参考 {@link OpenAiImageAutoConfiguration} openAiImageModel 方法
*/

View File

@ -6,7 +6,6 @@ import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatModel;
import reactor.core.publisher.Flux;
/**
@ -19,13 +18,14 @@ import reactor.core.publisher.Flux;
public class DouBaoChatModel implements ChatModel {
public static final String BASE_URL = "https://ark.cn-beijing.volces.com/api";
public static final String COMPLETE_PATH = "/v3/chat/completions";
public static final String MODEL_DEFAULT = "doubao-1-5-lite-32k-250115";
/**
* 兼容 OpenAI 接口进行复用
*/
private final OpenAiChatModel openAiChatModel;
private final ChatModel openAiChatModel;
@Override
public ChatResponse call(Prompt prompt) {

View File

@ -0,0 +1,46 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.gemini;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatModel;
import reactor.core.publisher.Flux;
/**
* 谷歌 Gemini {@link ChatModel} 实现类基于 Google AI Studio 提供的 <a href="https://ai.google.dev/gemini-api/docs/openai">OpenAI 兼容方案</a>
*
* @author 芋道源码
*/
@Slf4j
@RequiredArgsConstructor
public class GeminiChatModel implements ChatModel {
public static final String BASE_URL = "https://generativelanguage.googleapis.com/v1beta/openai/";
public static final String COMPLETE_PATH = "/chat/completions";
public static final String MODEL_DEFAULT = "gemini-2.5-flash";
/**
* 兼容 OpenAI 接口进行复用
*/
private final OpenAiChatModel openAiChatModel;
@Override
public ChatResponse call(Prompt prompt) {
return openAiChatModel.call(prompt);
}
@Override
public Flux<ChatResponse> stream(Prompt prompt) {
return openAiChatModel.stream(prompt);
}
@Override
public ChatOptions getDefaultOptions() {
return openAiChatModel.getDefaultOptions();
}
}

View File

@ -6,7 +6,6 @@ import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatModel;
import reactor.core.publisher.Flux;
/**
@ -22,6 +21,7 @@ import reactor.core.publisher.Flux;
public class HunYuanChatModel implements ChatModel {
public static final String BASE_URL = "https://api.hunyuan.cloud.tencent.com";
public static final String COMPLETE_PATH = "/v1/chat/completions";
public static final String MODEL_DEFAULT = "hunyuan-turbo";
@ -32,7 +32,7 @@ public class HunYuanChatModel implements ChatModel {
/**
* 兼容 OpenAI 接口进行复用
*/
private final OpenAiChatModel openAiChatModel;
private final ChatModel openAiChatModel;
@Override
public ChatResponse call(Prompt prompt) {

View File

@ -23,7 +23,7 @@ public class SiliconFlowChatModel implements ChatModel {
/**
* 兼容 OpenAI 接口进行复用
*/
private final OpenAiChatModel openAiChatModel;
private final ChatModel openAiChatModel;
@Override
public ChatResponse call(Prompt prompt) {

View File

@ -6,7 +6,6 @@ import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatModel;
import reactor.core.publisher.Flux;
/**
@ -18,28 +17,34 @@ import reactor.core.publisher.Flux;
@RequiredArgsConstructor
public class XingHuoChatModel implements ChatModel {
public static final String BASE_URL = "https://spark-api-open.xf-yun.com";
public static final String BASE_URL_V1 = "https://spark-api-open.xf-yun.com";
public static final String MODEL_DEFAULT = "generalv3.5";
public static final String BASE_URL_V2 = "https://spark-api-open.xf-yun.com";
public static final String BASE_COMPLETIONS_PATH_V2 = "/v2/chat/completions";
/**
* 兼容 OpenAI 接口进行复用
* 已知模型名列表x14.0Ultrageneralv3.5max-32kgeneralv3pro-128klite
*/
private final OpenAiChatModel openAiChatModel;
public static final String MODEL_DEFAULT = "4.0Ultra";
/**
* v1 兼容 OpenAI 接口进行复用
*/
private final ChatModel openAiChatModelV1;
@Override
public ChatResponse call(Prompt prompt) {
return openAiChatModel.call(prompt);
return openAiChatModelV1.call(prompt);
}
@Override
public Flux<ChatResponse> stream(Prompt prompt) {
return openAiChatModel.stream(prompt);
return openAiChatModelV1.stream(prompt);
}
@Override
public ChatOptions getDefaultOptions() {
return openAiChatModel.getDefaultOptions();
return openAiChatModelV1.getDefaultOptions();
}
}

View File

@ -0,0 +1,18 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.webserch;
/**
* 网络搜索客户端接口
*
* @author 芋道源码
*/
public interface AiWebSearchClient {
/**
* 网页搜索
*
* @param request 搜索请求
* @return 搜索结果
*/
AiWebSearchResponse search(AiWebSearchRequest request);
}

View File

@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.webserch;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Data
public class AiWebSearchRequest {
/**
* 用户的搜索词
*/
@NotEmpty(message = "搜索词不能为空")
private String query;
/**
* 是否显示文本摘要
*
* true - 显示
* false - 不显示默认
*/
private Boolean summary;
/**
* 返回结果的条数
*/
@NotNull(message = "返回结果条数不能为空")
@Min(message = "返回结果条数最小为 1", value = 1)
@Max(message = "返回结果条数最大为 50", value = 50)
private Integer count;
}

View File

@ -0,0 +1,62 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.webserch;
import lombok.Data;
import java.util.List;
@Data
public class AiWebSearchResponse {
/**
* 总数总共匹配的网页数
*/
private Long total;
/**
* 数据列表
*/
private List<WebPage> lists;
/**
* 网页对象
*/
@Data
public static class WebPage {
/**
* 名称
*
* 例如说搜狐网
*/
private String name;
/**
* 图标
*/
private String icon;
/**
* 标题
*
* 例如说186页|阿里巴巴2024年环境社会和治理ESG报告
*/
private String title;
/**
* URL
*
* 例如说https://m.sohu.com/a/815036254_121819701/?pvid=000115_3w_a
*/
@SuppressWarnings("JavadocLinkAsPlainText")
private String url;
/**
* 内容的简短描述
*/
private String snippet;
/**
* 内容的文本摘要
*/
private String summary;
}
}

View File

@ -0,0 +1,153 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.webserch.bocha;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.ai.framework.ai.core.webserch.AiWebSearchClient;
import cn.iocoder.yudao.module.ai.framework.ai.core.webserch.AiWebSearchRequest;
import cn.iocoder.yudao.module.ai.framework.ai.core.webserch.AiWebSearchResponse;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
/**
* 博查 {@link AiWebSearchClient} 实现类
*
* @see <a href="https://open.bochaai.com/overview">博查 AI 开放平台</a>
*
* @author 芋道源码
*/
@Slf4j
public class AiBoChaWebSearchClient implements AiWebSearchClient {
public static final String BASE_URL = "https://api.bochaai.com";
private static final String AUTHORIZATION_HEADER = "Authorization";
private static final String BEARER_PREFIX = "Bearer ";
private final WebClient webClient;
private final Predicate<HttpStatusCode> STATUS_PREDICATE = status -> !status.is2xxSuccessful();
private final Function<Object, Function<ClientResponse, Mono<? extends Throwable>>> EXCEPTION_FUNCTION =
reqParam -> response -> response.bodyToMono(String.class).handle((responseBody, sink) -> {
log.error("[AiBoChaWebSearchClient] 调用失败!请求参数:[{}],响应数据: [{}]", reqParam, responseBody);
sink.error(new IllegalStateException("[AiBoChaWebSearchClient] 调用失败!"));
});
public AiBoChaWebSearchClient(String apiKey) {
this.webClient = WebClient.builder()
.baseUrl(BASE_URL)
.defaultHeaders((headers) -> {
headers.setContentType(MediaType.APPLICATION_JSON);
headers.add(AUTHORIZATION_HEADER, BEARER_PREFIX + apiKey);
})
.build();
}
@Override
public AiWebSearchResponse search(AiWebSearchRequest request) {
// 转换请求参数
WebSearchRequest webSearchRequest = new WebSearchRequest(
request.getQuery(),
request.getSummary(),
request.getCount()
);
// 调用博查 API
CommonResult<WebSearchResponse> response = this.webClient.post()
.uri("/v1/web-search")
.bodyValue(webSearchRequest)
.retrieve()
.onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(webSearchRequest))
.bodyToMono(new ParameterizedTypeReference<CommonResult<WebSearchResponse>>() {})
.block();
if (response == null) {
throw new IllegalStateException("[search][搜索结果为空]");
}
if (response.getData() == null) {
throw new IllegalStateException(String.format("[search][搜索失败code = %s, msg = %s]",
response.getCode(), response.getMsg()));
}
WebSearchResponse data = response.getData();
// 转换结果
AiWebSearchResponse result = new AiWebSearchResponse();
if (data.webPages() == null || CollUtil.isEmpty(data.webPages().value())) {
return result.setTotal(0L).setLists(List.of());
}
return result.setTotal(data.webPages().totalEstimatedMatches())
.setLists(convertList(data.webPages().value(), page -> new AiWebSearchResponse.WebPage()
.setName(page.siteName()).setIcon(page.siteIcon())
.setTitle(page.name()).setUrl(page.url())
.setSnippet(page.snippet()).setSummary(page.summary())));
}
/**
* 网页搜索请求参数
*/
@JsonInclude(value = JsonInclude.Include.NON_NULL)
public record WebSearchRequest(
String query,
Boolean summary,
Integer count
) {
public WebSearchRequest {
Assert.notBlank(query, "query 不能为空");
}
}
/**
* 网页搜索响应
*/
@JsonInclude(value = JsonInclude.Include.NON_NULL)
public record WebSearchResponse(
WebSearchWebPages webPages
) {
}
/**
* 网页搜索结果
*/
@JsonInclude(value = JsonInclude.Include.NON_NULL)
public record WebSearchWebPages(
String webSearchUrl,
Long totalEstimatedMatches,
List<WebPageValue> value,
Boolean someResultsRemoved
) {
/**
* 网页结果值
*/
@JsonInclude(value = JsonInclude.Include.NON_NULL)
public record WebPageValue(
String id,
String name,
String url,
String displayUrl,
String snippet,
String summary,
String siteName,
String siteIcon,
String datePublished,
String dateLastCrawled,
String cachedPageUrl,
String language,
Boolean isFamilyFriendly,
Boolean isNavigational
) {
}
}
}

View File

@ -0,0 +1,38 @@
package cn.iocoder.yudao.module.ai.framework.security.config;
import cn.iocoder.yudao.framework.security.config.AuthorizeRequestsCustomizer;
import jakarta.annotation.Resource;
import org.springframework.ai.mcp.server.autoconfigure.McpServerProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer;
import java.util.Optional;
/**
* AI 模块的 Security 配置
*/
@Configuration(proxyBeanMethods = false, value = "aiSecurityConfiguration")
public class SecurityConfiguration {
@Resource
private Optional<McpServerProperties> serverProperties;
@Bean("aiAuthorizeRequestsCustomizer")
public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() {
return new AuthorizeRequestsCustomizer() {
@Override
public void customize(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry registry) {
// MCP Server
serverProperties.ifPresent(properties -> {
registry.requestMatchers(properties.getSseEndpoint()).permitAll();
registry.requestMatchers(properties.getSseMessageEndpoint()).permitAll();
});
}
};
}
}

View File

@ -0,0 +1,4 @@
/**
* 占位
*/
package cn.iocoder.yudao.module.ai.framework.security.core;

View File

@ -1,10 +1,11 @@
package cn.iocoder.yudao.module.ai.service.chat;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum;
import cn.iocoder.yudao.module.ai.util.AiUtils;
import cn.hutool.http.HttpUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
@ -21,6 +22,10 @@ import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiModelDO;
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiToolDO;
import cn.iocoder.yudao.module.ai.dal.mysql.chat.AiChatMessageMapper;
import cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants;
import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum;
import cn.iocoder.yudao.module.ai.framework.ai.core.webserch.AiWebSearchClient;
import cn.iocoder.yudao.module.ai.framework.ai.core.webserch.AiWebSearchRequest;
import cn.iocoder.yudao.module.ai.framework.ai.core.webserch.AiWebSearchResponse;
import cn.iocoder.yudao.module.ai.service.knowledge.AiKnowledgeDocumentService;
import cn.iocoder.yudao.module.ai.service.knowledge.AiKnowledgeSegmentService;
import cn.iocoder.yudao.module.ai.service.knowledge.bo.AiKnowledgeSegmentSearchReqBO;
@ -28,6 +33,10 @@ import cn.iocoder.yudao.module.ai.service.knowledge.bo.AiKnowledgeSegmentSearchR
import cn.iocoder.yudao.module.ai.service.model.AiChatRoleService;
import cn.iocoder.yudao.module.ai.service.model.AiModelService;
import cn.iocoder.yudao.module.ai.service.model.AiToolService;
import cn.iocoder.yudao.module.ai.util.AiUtils;
import cn.iocoder.yudao.module.ai.util.FileTypeUtils;
import com.google.common.collect.Maps;
import io.modelcontextprotocol.client.McpSyncClient;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.messages.Message;
@ -39,6 +48,11 @@ import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.model.StreamingChatModel;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.mcp.SyncMcpToolCallbackProvider;
import org.springframework.ai.mcp.client.autoconfigure.properties.McpClientCommonProperties;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.resolution.ToolCallbackResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import reactor.core.publisher.Flux;
@ -64,6 +78,13 @@ import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.CHAT_MESSAGE_N
@Slf4j
public class AiChatMessageServiceImpl implements AiChatMessageService {
/**
* 联网搜索的结束数
*/
private static final Integer WEB_SEARCH_COUNT = 10;
// TODO @芋艿后续优化下对话的 Prompt 整体结构
/**
* 知识库转 {@link UserMessage} 的内容模版
*/
@ -71,6 +92,18 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
"%s\n\n" + // 多个 <Reference></Reference> 的拼接
"回答要求:\n- 避免提及你是从 <Reference></Reference> 获取的知识。";
private static final String WEB_SEARCH_USER_MESSAGE_TEMPLATE = "使用 <WebSearch></WebSearch> 标记中的内容作为本次对话的参考:\n\n" +
"%s\n\n" + // 多个 <WebSearch></WebSearch> 的拼接
"回答要求:\n- 避免提及你是从 <WebSearch></WebSearch> 获取的知识。";
/**
* 附件转 ${@link UserMessage} 的内容模版
*/
@SuppressWarnings("TextBlockMigration")
private static final String Attachment_USER_MESSAGE_TEMPLATE = "使用 <Attachment></Attachment> 标记用户对话上传的附件内容:\n\n" +
"%s\n\n" + // 多个 <Attachment></Attachment> 的拼接
"回答要求:\n- 避免提及 <Attachment></Attachment> 附件的编码格式。";
@Resource
private AiChatMessageMapper chatMessageMapper;
@ -87,6 +120,21 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
@Resource
private AiToolService toolService;
@SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")
@Autowired(required = false) // 由于 yudao.ai.web-search.enable 配置项可以关闭 AiWebSearchClient 的功能所以这里只能不强制注入
private AiWebSearchClient webSearchClient;
@SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")
@Autowired(required = false) // 由于 yudao.ai.mcp.client.enable 配置项可以关闭 McpSyncClient 的功能所以这里只能不强制注入
private List<McpSyncClient> mcpClients;
@SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")
@Autowired(required = false) // 由于 yudao.ai.mcp.client.enable 配置项可以关闭 McpSyncClient 的功能所以这里只能不强制注入
private McpClientCommonProperties mcpClientCommonProperties;
@Resource
private ToolCallbackResolver toolCallbackResolver;
@Transactional(rollbackFor = Exception.class)
public AiChatMessageSendRespVO sendMessage(AiChatMessageSendReqVO sendReqVO, Long userId) {
// 1.1 校验对话存在
@ -100,27 +148,35 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
AiModelDO model = modalService.validateModel(conversation.getModelId());
ChatModel chatModel = modalService.getChatModel(model.getId());
// 2. 知识库找回
List<AiKnowledgeSegmentSearchRespBO> knowledgeSegments = recallKnowledgeSegment(sendReqVO.getContent(), conversation);
// 2.1 知识库召回
List<AiKnowledgeSegmentSearchRespBO> knowledgeSegments = recallKnowledgeSegment(
sendReqVO.getContent(), conversation);
// 2.2 联网搜索
AiWebSearchResponse webSearchResponse = Boolean.TRUE.equals(sendReqVO.getUseSearch()) && webSearchClient != null ?
webSearchClient.search(new AiWebSearchRequest().setQuery(sendReqVO.getContent())
.setSummary(true).setCount(WEB_SEARCH_COUNT)) : null;
// 3. 插入 user 发送消息
AiChatMessageDO userMessage = createChatMessage(conversation.getId(), null, model,
userId, conversation.getRoleId(), MessageType.USER, sendReqVO.getContent(), sendReqVO.getUseContext(),
null);
null, sendReqVO.getAttachmentUrls(), null);
// 3.1 插入 assistant 接收消息
// 4.1 插入 assistant 接收消息
AiChatMessageDO assistantMessage = createChatMessage(conversation.getId(), userMessage.getId(), model,
userId, conversation.getRoleId(), MessageType.ASSISTANT, "", sendReqVO.getUseContext(),
knowledgeSegments);
knowledgeSegments, null, webSearchResponse);
// 3.2 创建 chat 需要的 Prompt
Prompt prompt = buildPrompt(conversation, historyMessages, knowledgeSegments, model, sendReqVO);
// 4.2 创建 chat 需要的 Prompt
Prompt prompt = buildPrompt(conversation, historyMessages, knowledgeSegments, webSearchResponse, model, sendReqVO);
ChatResponse chatResponse = chatModel.call(prompt);
// 3.3 更新响应内容
String newContent = chatResponse.getResult().getOutput().getText();
chatMessageMapper.updateById(new AiChatMessageDO().setId(assistantMessage.getId()).setContent(newContent));
// 3.4 响应结果
// 4.3 更新响应内容
String newContent = AiUtils.getChatResponseContent(chatResponse);
String newReasoningContent = AiUtils.getChatResponseReasoningContent(chatResponse);
chatMessageMapper.updateById(new AiChatMessageDO().setId(assistantMessage.getId())
.setContent(newContent).setReasoningContent(newReasoningContent));
// 4.4 响应结果
Map<Long, AiKnowledgeDocumentDO> documentMap = knowledgeDocumentService.getKnowledgeDocumentMap(
convertSet(knowledgeSegments, AiKnowledgeSegmentSearchRespBO::getDocumentId));
List<AiChatMessageRespVO.KnowledgeSegment> segments = BeanUtils.toBean(knowledgeSegments,
@ -131,7 +187,8 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
return new AiChatMessageSendRespVO()
.setSend(BeanUtils.toBean(userMessage, AiChatMessageSendRespVO.Message.class))
.setReceive(BeanUtils.toBean(assistantMessage, AiChatMessageSendRespVO.Message.class)
.setContent(newContent).setSegments(segments));
.setContent(newContent).setSegments(segments)
.setWebSearchPages(webSearchResponse != null ? webSearchResponse.getLists() : null));
}
@Override
@ -148,29 +205,36 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
AiModelDO model = modalService.validateModel(conversation.getModelId());
StreamingChatModel chatModel = modalService.getChatModel(model.getId());
// 2. 知识库找回
List<AiKnowledgeSegmentSearchRespBO> knowledgeSegments = recallKnowledgeSegment(sendReqVO.getContent(),
conversation);
// 2.1 知识库找回
List<AiKnowledgeSegmentSearchRespBO> knowledgeSegments = recallKnowledgeSegment(
sendReqVO.getContent(), conversation);
// 2.2 联网搜索
AiWebSearchResponse webSearchResponse = Boolean.TRUE.equals(sendReqVO.getUseSearch()) && webSearchClient != null ?
webSearchClient.search(new AiWebSearchRequest().setQuery(sendReqVO.getContent())
.setSummary(true).setCount(WEB_SEARCH_COUNT)) : null;
// 3. 插入 user 发送消息
AiChatMessageDO userMessage = createChatMessage(conversation.getId(), null, model,
userId, conversation.getRoleId(), MessageType.USER, sendReqVO.getContent(), sendReqVO.getUseContext(),
null);
null, sendReqVO.getAttachmentUrls(), null);
// 4.1 插入 assistant 接收消息
AiChatMessageDO assistantMessage = createChatMessage(conversation.getId(), userMessage.getId(), model,
userId, conversation.getRoleId(), MessageType.ASSISTANT, "", sendReqVO.getUseContext(),
knowledgeSegments);
knowledgeSegments, null, webSearchResponse);
// 4.2 构建 Prompt并进行调用
Prompt prompt = buildPrompt(conversation, historyMessages, knowledgeSegments, model, sendReqVO);
Prompt prompt = buildPrompt(conversation, historyMessages, knowledgeSegments, webSearchResponse, model, sendReqVO);
Flux<ChatResponse> streamResponse = chatModel.stream(prompt);
// 4.3 流式返回
StringBuffer contentBuffer = new StringBuffer();
StringBuffer reasoningContentBuffer = new StringBuffer();
return streamResponse.map(chunk -> {
// 处理知识库的返回只有首次才有
// 仅首次返回知识库联网搜索
List<AiChatMessageRespVO.KnowledgeSegment> segments = null;
List<AiWebSearchResponse.WebPage> webSearchPages = null;
if (StrUtil.isEmpty(contentBuffer)) {
Map<Long, AiKnowledgeDocumentDO> documentMap = TenantUtils.executeIgnore(() ->
knowledgeDocumentService.getKnowledgeDocumentMap(
@ -179,24 +243,56 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
AiKnowledgeDocumentDO document = documentMap.get(segment.getDocumentId());
segment.setDocumentName(document != null ? document.getName() : null);
});
if (webSearchResponse != null) {
webSearchPages = webSearchResponse.getLists();
}
}
// 响应结果
String newContent = chunk.getResult() != null ? chunk.getResult().getOutput().getText() : null;
newContent = StrUtil.nullToDefault(newContent, ""); // 避免 null 情况
contentBuffer.append(newContent);
String newContent = AiUtils.getChatResponseContent(chunk);
String newReasoningContent = AiUtils.getChatResponseReasoningContent(chunk);
if (StrUtil.isNotEmpty(newContent)) {
contentBuffer.append(newContent);
}
if (StrUtil.isNotEmpty(newReasoningContent)) {
reasoningContentBuffer.append(newReasoningContent);
}
return success(new AiChatMessageSendRespVO()
.setSend(BeanUtils.toBean(userMessage, AiChatMessageSendRespVO.Message.class))
.setReceive(BeanUtils.toBean(assistantMessage, AiChatMessageSendRespVO.Message.class)
.setContent(newContent).setSegments(segments)));
.setContent(StrUtil.nullToDefault(newContent, "")) // 避免 null 情况
.setReasoningContent(StrUtil.nullToDefault(newReasoningContent, "")) // 避免 null 情况
.setSegments(segments).setWebSearchPages(webSearchPages))); // 知识库 + 联网搜索
}).doOnComplete(() -> {
// 忽略租户因为 Flux 异步无法透传租户
TenantUtils.executeIgnore(() -> chatMessageMapper.updateById(
new AiChatMessageDO().setId(assistantMessage.getId()).setContent(contentBuffer.toString())));
new AiChatMessageDO().setId(assistantMessage.getId()).setContent(contentBuffer.toString())
.setReasoningContent(reasoningContentBuffer.toString())));
}).doOnError(throwable -> {
log.error("[sendChatMessageStream][userId({}) sendReqVO({}) 发生异常]", userId, sendReqVO, throwable);
// 忽略租户因为 Flux 异步无法透传租户
TenantUtils.executeIgnore(() -> chatMessageMapper.updateById(
new AiChatMessageDO().setId(assistantMessage.getId()).setContent(throwable.getMessage())));
TenantUtils.executeIgnore(() -> {
// 如果有内容则更新内容
if (StrUtil.isNotEmpty(contentBuffer)) {
chatMessageMapper.updateById(new AiChatMessageDO().setId(assistantMessage.getId())
.setContent(contentBuffer.toString()).setReasoningContent(reasoningContentBuffer.toString()));
} else {
// 否则则进行删除
chatMessageMapper.deleteById(assistantMessage.getId());
}
});
}).doOnCancel(() -> {
log.info("[sendChatMessageStream][userId({}) sendReqVO({}) 取消请求]", userId, sendReqVO);
// 忽略租户因为 Flux 异步无法透传租户
TenantUtils.executeIgnore(() -> {
// 如果有内容则更新内容
if (StrUtil.isNotEmpty(contentBuffer)) {
chatMessageMapper.updateById(new AiChatMessageDO().setId(assistantMessage.getId())
.setContent(contentBuffer.toString()).setReasoningContent(reasoningContentBuffer.toString()));
} else {
// 否则则进行删除
chatMessageMapper.deleteById(assistantMessage.getId());
}
});
}).onErrorResume(error -> Flux.just(error(ErrorCodeConstants.CHAT_STREAM_ERROR)));
}
@ -211,7 +307,7 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
return Collections.emptyList();
}
// 2. 遍历
// 2. 遍历
List<AiKnowledgeSegmentSearchRespBO> knowledgeSegments = new ArrayList<>();
for (Long knowledgeId : role.getKnowledgeIds()) {
knowledgeSegments.addAll(knowledgeSegmentService.searchKnowledgeSegment(new AiKnowledgeSegmentSearchReqBO()
@ -222,6 +318,7 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
private Prompt buildPrompt(AiChatConversationDO conversation, List<AiChatMessageDO> messages,
List<AiKnowledgeSegmentSearchRespBO> knowledgeSegments,
AiWebSearchResponse webSearchResponse,
AiModelDO model, AiChatMessageSendReqVO sendReqVO) {
List<Message> chatMessages = new ArrayList<>();
// 1.1 System Context 角色设定
@ -231,8 +328,14 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
// 1.2 历史 history message 历史消息
List<AiChatMessageDO> contextMessages = filterContextMessages(messages, conversation, sendReqVO);
contextMessages
.forEach(message -> chatMessages.add(AiUtils.buildMessage(message.getType(), message.getContent())));
contextMessages.forEach(message -> {
chatMessages.add(AiUtils.buildMessage(message.getType(), message.getContent()));
UserMessage attachmentUserMessage = buildAttachmentUserMessage(message.getAttachmentUrls());
if (attachmentUserMessage != null) {
chatMessages.add(attachmentUserMessage);
}
// TODO @芋艿历史的知识库历史的搜索要不要拼接
});
// 1.3 当前 user message 新发送消息
chatMessages.add(new UserMessage(sendReqVO.getContent()));
@ -245,23 +348,76 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
chatMessages.add(new UserMessage(String.format(KNOWLEDGE_USER_MESSAGE_TEMPLATE, reference)));
}
// 2.1 查询 tool 工具
Set<String> toolNames = null;
Map<String,Object> toolContext = Map.of();
if (conversation.getRoleId() != null) {
AiChatRoleDO chatRole = chatRoleService.getChatRole(conversation.getRoleId());
if (chatRole != null && CollUtil.isNotEmpty(chatRole.getToolIds())) {
toolNames = convertSet(toolService.getToolList(chatRole.getToolIds()), AiToolDO::getName);
toolContext = AiUtils.buildCommonToolContext();
// 1.5 联网搜索通过 UserMessage 实现
if (webSearchResponse != null && CollUtil.isNotEmpty(webSearchResponse.getLists())) {
String webSearch = webSearchResponse.getLists().stream()
.map(page -> {
String summary = StrUtil.isNotEmpty(page.getSummary()) ?
"\nSummary: " + page.getSummary() : "";
return "<WebSearch title=\"" + page.getTitle() + "\" url=\"" + page.getUrl() + "\">"
+ StrUtil.blankToDefault(page.getSummary(), page.getSnippet()) + "</WebSearch>";
})
.collect(Collectors.joining("\n\n"));
chatMessages.add(new UserMessage(String.format(WEB_SEARCH_USER_MESSAGE_TEMPLATE, webSearch)));
}
// 1.6 附件通过 UserMessage 实现
if (CollUtil.isNotEmpty(sendReqVO.getAttachmentUrls())) {
UserMessage attachmentUserMessage = buildAttachmentUserMessage(sendReqVO.getAttachmentUrls());
if (attachmentUserMessage != null) {
chatMessages.add(attachmentUserMessage);
}
}
// 2.1 查询 tool 工具
List<ToolCallback> toolCallbacks = getToolCallbackListByRoleId(conversation.getRoleId());
Map<String,Object> toolContext = CollUtil.isNotEmpty(toolCallbacks) ? AiUtils.buildCommonToolContext()
: Map.of();
// 2.2 构建 ChatOptions 对象
AiPlatformEnum platform = AiPlatformEnum.validatePlatform(model.getPlatform());
ChatOptions chatOptions = AiUtils.buildChatOptions(platform, model.getModel(),
conversation.getTemperature(), conversation.getMaxTokens(), toolNames, toolContext);
conversation.getTemperature(), conversation.getMaxTokens(),
toolCallbacks, toolContext);
return new Prompt(chatMessages, chatOptions);
}
private List<ToolCallback> getToolCallbackListByRoleId(Long roleId) {
if (roleId == null) {
return null;
}
AiChatRoleDO chatRole = chatRoleService.getChatRole(roleId);
if (chatRole == null) {
return null;
}
List<ToolCallback> toolCallbacks = new ArrayList<>();
// 1. 通过 toolIds
if (CollUtil.isNotEmpty(chatRole.getToolIds())) {
Set<String> toolNames = convertSet(toolService.getToolList(chatRole.getToolIds()), AiToolDO::getName);
toolNames.forEach(toolName -> {
ToolCallback toolCallback = toolCallbackResolver.resolve(toolName);
if (toolCallback != null) {
toolCallbacks.add(toolCallback);
}
});
}
// 2. 通过 mcpClients
if (CollUtil.isNotEmpty(mcpClients) && CollUtil.isNotEmpty(chatRole.getMcpClientNames())) {
chatRole.getMcpClientNames().forEach(mcpClientName -> {
// 2.1 标准化名字参考 McpClientAutoConfiguration connectedClientName 方法
String finalMcpClientName = mcpClientCommonProperties.getName() + " - " + mcpClientName;
// 2.2 匹配对应的 McpSyncClient
mcpClients.forEach(mcpClient -> {
if (ObjUtil.notEqual(mcpClient.getClientInfo().name(), finalMcpClientName)) {
return;
}
ToolCallback[] mcpToolCallBacks = new SyncMcpToolCallbackProvider(mcpClient).getToolCallbacks();
CollUtil.addAll(toolCallbacks, mcpToolCallBacks);
});
});
}
return toolCallbacks;
}
/**
* 从历史消息中获得倒序的 n 组消息作为消息上下文
* <p>
@ -302,14 +458,56 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
return contextMessages;
}
private UserMessage buildAttachmentUserMessage(List<String> attachmentUrls) {
if (CollUtil.isEmpty(attachmentUrls)) {
return null;
}
// 读取文件内容
Map<String, String> attachmentContents = Maps.newLinkedHashMapWithExpectedSize(attachmentUrls.size());
for (String attachmentUrl : attachmentUrls) {
try {
String name = FileNameUtil.getName(attachmentUrl);
String mineType = FileTypeUtils.getMineType(name);
String content;
if (FileTypeUtils.isImage(mineType)) {
// 特殊图片则转为 Base64
byte[] bytes = HttpUtil.downloadBytes(attachmentUrl);
content = Base64.encode(bytes);
} else {
content = knowledgeDocumentService.readUrl(attachmentUrl);
}
if (StrUtil.isNotEmpty(content)) {
attachmentContents.put(name, content);
}
} catch (Exception e) {
log.error("[buildAttachmentUserMessage][读取附件({}) 发生异常]", attachmentUrl, e);
}
}
if (CollUtil.isEmpty(attachmentContents)) {
return null;
}
// 拼接 UserMessage 消息
String attachment = attachmentContents.entrySet().stream()
.map(entry -> "<Attachment name=\"" + entry.getKey() + "\">" + entry.getValue() + "</Attachment>")
.collect(Collectors.joining("\n\n"));
return new UserMessage(String.format(Attachment_USER_MESSAGE_TEMPLATE, attachment));
}
private AiChatMessageDO createChatMessage(Long conversationId, Long replyId,
AiModelDO model, Long userId, Long roleId,
MessageType messageType, String content, Boolean useContext,
List<AiKnowledgeSegmentSearchRespBO> knowledgeSegments) {
AiModelDO model, Long userId, Long roleId,
MessageType messageType, String content, Boolean useContext,
List<AiKnowledgeSegmentSearchRespBO> knowledgeSegments,
List<String> attachmentUrls,
AiWebSearchResponse webSearchResponse) {
AiChatMessageDO message = new AiChatMessageDO().setConversationId(conversationId).setReplyId(replyId)
.setModel(model.getModel()).setModelId(model.getId()).setUserId(userId).setRoleId(roleId)
.setType(messageType.getValue()).setContent(content).setUseContext(useContext)
.setSegmentIds(convertList(knowledgeSegments, AiKnowledgeSegmentSearchRespBO::getId));
.setSegmentIds(convertList(knowledgeSegments, AiKnowledgeSegmentSearchRespBO::getId))
.setAttachmentUrls(attachmentUrls);
if (webSearchResponse != null) {
message.setWebSearchPages(webSearchResponse.getLists());
}
message.setCreateTime(LocalDateTime.now());
chatMessageMapper.insert(message);
return message;

View File

@ -18,6 +18,10 @@ import cn.iocoder.yudao.module.ai.dal.mysql.knowledge.AiKnowledgeSegmentMapper;
import cn.iocoder.yudao.module.ai.service.knowledge.bo.AiKnowledgeSegmentSearchReqBO;
import cn.iocoder.yudao.module.ai.service.knowledge.bo.AiKnowledgeSegmentSearchRespBO;
import cn.iocoder.yudao.module.ai.service.model.AiModelService;
import com.alibaba.cloud.ai.dashscope.rerank.DashScopeRerankOptions;
import com.alibaba.cloud.ai.model.RerankModel;
import com.alibaba.cloud.ai.model.RerankRequest;
import com.alibaba.cloud.ai.model.RerankResponse;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.document.Document;
@ -27,6 +31,7 @@ import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.filter.FilterExpressionBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
@ -36,6 +41,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.KNOWLEDGE_SEGMENT_CONTENT_TOO_LONG;
import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.KNOWLEDGE_SEGMENT_NOT_EXISTS;
import static org.springframework.ai.vectorstore.SearchRequest.SIMILARITY_THRESHOLD_ACCEPT_ALL;
/**
* AI 知识库分片 Service 实现类
@ -55,6 +61,11 @@ public class AiKnowledgeSegmentServiceImpl implements AiKnowledgeSegmentService
VECTOR_STORE_METADATA_DOCUMENT_ID, String.class,
VECTOR_STORE_METADATA_SEGMENT_ID, String.class);
/**
* Rerank 在向量检索时检索数量 * 该系数目的是为了提升 Rerank 的效果
*/
private static final Integer RERANK_RETRIEVAL_FACTOR = 4;
@Resource
private AiKnowledgeSegmentMapper segmentMapper;
@ -69,6 +80,9 @@ public class AiKnowledgeSegmentServiceImpl implements AiKnowledgeSegmentService
@Resource
private TokenCountEstimator tokenCountEstimator;
@Autowired(required = false) // 由于 spring.ai.model.rerank 配置项可以关闭 RerankModel 的功能所以这里只能不强制注入
private RerankModel rerankModel;
@Override
public PageResult<AiKnowledgeSegmentDO> getKnowledgeSegmentPage(AiKnowledgeSegmentPageReqVO pageReqVO) {
return segmentMapper.selectPage(pageReqVO);
@ -211,28 +225,16 @@ public class AiKnowledgeSegmentServiceImpl implements AiKnowledgeSegmentService
// 1. 校验
AiKnowledgeDO knowledge = knowledgeService.validateKnowledgeExists(reqBO.getKnowledgeId());
// 2.1 向量检索
VectorStore vectorStore = getVectorStoreById(knowledge);
List<Document> documents = vectorStore.similaritySearch(SearchRequest.builder()
.query(reqBO.getContent())
.topK(ObjUtil.defaultIfNull(reqBO.getTopK(), knowledge.getTopK()))
.similarityThreshold(
ObjUtil.defaultIfNull(reqBO.getSimilarityThreshold(), knowledge.getSimilarityThreshold()))
.filterExpression(new FilterExpressionBuilder()
.eq(VECTOR_STORE_METADATA_KNOWLEDGE_ID, reqBO.getKnowledgeId().toString())
.build())
.build());
if (CollUtil.isEmpty(documents)) {
return ListUtil.empty();
}
// 2.2 段落召回
// 2. 检索
List<Document> documents = searchDocument(knowledge, reqBO);
// 3.1 段落召回
List<AiKnowledgeSegmentDO> segments = segmentMapper
.selectListByVectorIds(convertList(documents, Document::getId));
if (CollUtil.isEmpty(segments)) {
return ListUtil.empty();
}
// 3. 增加召回次数
// 3.2 增加召回次数
segmentMapper.updateRetrievalCountIncrByIds(convertList(segments, AiKnowledgeSegmentDO::getId));
// 4. 构建结果
@ -249,6 +251,42 @@ public class AiKnowledgeSegmentServiceImpl implements AiKnowledgeSegmentService
return result;
}
/**
* 基于 Embedding + Rerank Model检索知识库中的文档
*
* @param knowledge 知识库
* @param reqBO 检索请求
* @return 文档列表
*/
private List<Document> searchDocument(AiKnowledgeDO knowledge, AiKnowledgeSegmentSearchReqBO reqBO) {
VectorStore vectorStore = getVectorStoreById(knowledge);
Integer topK = ObjUtil.defaultIfNull(reqBO.getTopK(), knowledge.getTopK());
Double similarityThreshold = ObjUtil.defaultIfNull(reqBO.getSimilarityThreshold(), knowledge.getSimilarityThreshold());
// 1. 向量检索
int searchTopK = rerankModel != null ? topK * RERANK_RETRIEVAL_FACTOR : topK;
double searchSimilarityThreshold = rerankModel != null ? SIMILARITY_THRESHOLD_ACCEPT_ALL : similarityThreshold;
SearchRequest.Builder searchRequestBuilder = SearchRequest.builder()
.query(reqBO.getContent())
.topK(searchTopK).similarityThreshold(searchSimilarityThreshold)
.filterExpression(new FilterExpressionBuilder()
.eq(VECTOR_STORE_METADATA_KNOWLEDGE_ID, reqBO.getKnowledgeId().toString()).build());
List<Document> documents = vectorStore.similaritySearch(searchRequestBuilder.build());
if (CollUtil.isEmpty(documents)) {
return documents;
}
// 2. Rerank 重排序
if (rerankModel != null) {
RerankResponse rerankResponse = rerankModel.call(new RerankRequest(reqBO.getContent(), documents,
DashScopeRerankOptions.builder().withTopN(topK).build()));
documents = convertList(rerankResponse.getResults(),
documentWithScore -> documentWithScore.getScore() >= similarityThreshold
? documentWithScore.getOutput() : null);
}
return documents;
}
@Override
public List<AiKnowledgeSegmentDO> splitContent(String url, Integer segmentMaxTokens) {
// 1. 读取 URL 内容

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.ai.service.model;
import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum;
import cn.iocoder.yudao.module.ai.framework.ai.core.AiModelFactory;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.AiModelFactory;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.midjourney.api.MidjourneyApi;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.suno.api.SunoApi;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;

View File

@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.ai.service.model;
import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.ai.controller.admin.model.vo.tool.AiToolPageReqVO;
@ -8,7 +7,8 @@ import cn.iocoder.yudao.module.ai.controller.admin.model.vo.tool.AiToolSaveReqVO
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiToolDO;
import cn.iocoder.yudao.module.ai.dal.mysql.model.AiToolMapper;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.resolution.ToolCallbackResolver;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
@ -31,6 +31,9 @@ public class AiToolServiceImpl implements AiToolService {
@Resource
private AiToolMapper toolMapper;
@Resource
private ToolCallbackResolver toolCallbackResolver;
@Override
public Long createTool(AiToolSaveReqVO createReqVO) {
// 校验名称是否存在
@ -70,9 +73,8 @@ public class AiToolServiceImpl implements AiToolService {
}
private void validateToolNameExists(String name) {
try {
SpringUtil.getBean(name);
} catch (NoSuchBeanDefinitionException e) {
ToolCallback toolCallback = toolCallbackResolver.resolve(name);
if (toolCallback == null) {
throw exception(TOOL_NAME_NOT_EXISTS, name);
}
}

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.ai.service.model.tool;
package cn.iocoder.yudao.module.ai.tool.function;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.io.FileUtil;

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.ai.service.model.tool;
package cn.iocoder.yudao.module.ai.tool.function;
import cn.iocoder.yudao.module.ai.util.AiUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.ai.service.model.tool;
package cn.iocoder.yudao.module.ai.tool.function;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.RandomUtil;

View File

@ -0,0 +1,4 @@
/**
* 参考 <a href="https://docs.spring.io/spring-ai/reference/api/tools.html#_methods_as_tools">Tool Calling Methods as Tools</a>
*/
package cn.iocoder.yudao.module.ai.tool.function;

View File

@ -0,0 +1,19 @@
package cn.iocoder.yudao.module.ai.tool.method;
/**
* 来自 Spring AI 官方文档
*
* Represents a person with basic information.
* This is an immutable record.
*/
public record Person(
int id,
String firstName,
String lastName,
String email,
String sex,
String ipAddress,
String jobTitle,
int age
) {
}

View File

@ -0,0 +1,80 @@
package cn.iocoder.yudao.module.ai.tool.method;
import java.util.List;
import java.util.Optional;
/**
* 来自 Spring AI 官方文档
*
* Service interface for managing Person data.
* Defines the contract for CRUD operations and search/filter functionalities.
*/
public interface PersonService {
/**
* Creates a new Person record.
* Assigns a unique ID to the person and stores it.
*
* @param personData The data for the new person (ID field is ignored). Must not be null.
* @return The created Person record, including the generated ID.
*/
Person createPerson(Person personData);
/**
* Retrieves a Person by their unique ID.
*
* @param id The ID of the person to retrieve.
* @return An Optional containing the found Person, or an empty Optional if not found.
*/
Optional<Person> getPersonById(int id);
/**
* Retrieves all Person records currently stored.
*
* @return An unmodifiable List containing all Persons. Returns an empty list if none exist.
*/
List<Person> getAllPersons();
/**
* Updates an existing Person record identified by ID.
* Replaces the existing data with the provided data, keeping the original ID.
*
* @param id The ID of the person to update.
* @param updatedPersonData The new data for the person (ID field is ignored). Must not be null.
* @return true if the person was found and updated, false otherwise.
*/
boolean updatePerson(int id, Person updatedPersonData);
/**
* Deletes a Person record identified by ID.
*
* @param id The ID of the person to delete.
* @return true if the person was found and deleted, false otherwise.
*/
boolean deletePerson(int id);
/**
* Searches for Persons whose job title contains the given query string (case-insensitive).
*
* @param jobTitleQuery The string to search for within job titles. Can be null or blank.
* @return An unmodifiable List of matching Persons. Returns an empty list if no matches or query is invalid.
*/
List<Person> searchByJobTitle(String jobTitleQuery);
/**
* Filters Persons by their exact sex (case-insensitive).
*
* @param sex The sex to filter by (e.g., "Male", "Female"). Can be null or blank.
* @return An unmodifiable List of matching Persons. Returns an empty list if no matches or filter is invalid.
*/
List<Person> filterBySex(String sex);
/**
* Filters Persons by their exact age.
*
* @param age The age to filter by.
* @return An unmodifiable List of matching Persons. Returns an empty list if no matches.
*/
List<Person> filterByAge(int age);
}

View File

@ -0,0 +1,336 @@
package cn.iocoder.yudao.module.ai.tool.method;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 来自 Spring AI 官方文档
*
* Implementation of the PersonService interface using an in-memory data store.
* Manages a collection of Person objects loaded from embedded CSV data.
* This class is thread-safe due to the use of ConcurrentHashMap and AtomicInteger.
*/
@Service
@Slf4j
public class PersonServiceImpl implements PersonService {
private final Map<Integer, Person> personStore = new ConcurrentHashMap<>();
private AtomicInteger idGenerator;
/**
* Embedded CSV data for initial population
*/
private static final String CSV_DATA = """
Id,FirstName,LastName,Email,Sex,IpAddress,JobTitle,Age
1,Fons,Tollfree,ftollfree0@senate.gov,Male,55.1 Tollfree Lane,Research Associate,31
2,Emlynne,Tabourier,etabourier1@networksolutions.com,Female,18 Tabourier Way,Associate Professor,38
3,Shae,Johncey,sjohncey2@yellowpages.com,Male,1 Johncey Circle,Structural Analysis Engineer,30
4,Sebastien,Bradly,sbradly3@mapquest.com,Male,2 Bradly Hill,Chief Executive Officer,40
5,Harriott,Kitteringham,hkitteringham4@typepad.com,Female,3 Kitteringham Drive,VP Sales,47
6,Anallise,Parradine,aparradine5@miibeian.gov.cn,Female,4 Parradine Street,Analog Circuit Design manager,44
7,Gorden,Kirkbright,gkirkbright6@reuters.com,Male,5 Kirkbright Plaza,Senior Editor,40
8,Veradis,Ledwitch,vledwitch7@google.com.au,Female,6 Ledwitch Avenue,Computer Systems Analyst IV,44
9,Agnesse,Penhalurick,apenhalurick8@google.it,Female,7 Penhalurick Terrace,Automation Specialist IV,41
10,Bibby,Hutable,bhutable9@craigslist.org,Female,8 Hutable Place,Account Representative I,43
11,Karoly,Lightoller,klightollera@rakuten.co.jp,Female,9 Lightoller Parkway,Senior Developer,46
12,Cristine,Durrad,cdurradb@aol.com,Female,10 Durrad Center,Senior Developer,48
13,Aggy,Napier,anapierc@hostgator.com,Female,11 Napier Court,VP Product Management,44
14,Prisca,Caddens,pcaddensd@vinaora.com,Female,12 Caddens Alley,Business Systems Development Analyst,41
15,Khalil,McKernan,kmckernane@google.fr,Male,13 McKernan Pass,Engineer IV,44
16,Lorry,MacTrusty,lmactrustyf@eventbrite.com,Male,14 MacTrusty Junction,Design Engineer,42
17,Casandra,Worsell,cworsellg@goo.gl,Female,15 Worsell Point,Systems Administrator IV,45
18,Ulrikaumeko,Haveline,uhavelineh@usgs.gov,Female,16 Haveline Trail,Financial Advisor,42
19,Shurlocke,Albany,salbanyi@artisteer.com,Male,17 Albany Plaza,Software Test Engineer III,46
20,Myrilla,Brimilcombe,mbrimilcombej@accuweather.com,Female,18 Brimilcombe Road,Programmer Analyst I,48
21,Carlina,Scimonelli,cscimonellik@va.gov,Female,19 Scimonelli Pass,Help Desk Technician,45
22,Tina,Goullee,tgoulleel@miibeian.gov.cn,Female,20 Goullee Crossing,Accountant IV,43
23,Adriaens,Storek,astorekm@devhub.com,Female,21 Storek Avenue,Recruiting Manager,40
24,Tedra,Giraudot,tgiraudotn@wiley.com,Female,22 Giraudot Terrace,Speech Pathologist,47
25,Josiah,Soares,jsoareso@google.nl,Male,23 Soares Street,Tax Accountant,45
26,Kayle,Gaukrodge,kgaukrodgep@wikispaces.com,Female,24 Gaukrodge Parkway,Accountant II,43
27,Ardys,Chuter,achuterq@ustream.tv,Female,25 Chuter Drive,Engineer IV,41
28,Francyne,Baudinet,fbaudinetr@newyorker.com,Female,26 Baudinet Center,VP Accounting,48
29,Gerick,Bullan,gbullans@seesaa.net,Male,27 Bullan Way,Senior Financial Analyst,43
30,Northrup,Grivori,ngrivorit@unc.edu,Male,28 Grivori Plaza,Systems Administrator I,45
31,Town,Duguid,tduguidu@squarespace.com,Male,29 Duguid Pass,Safety Technician IV,46
32,Pierette,Kopisch,pkopischv@google.com.br,Female,30 Kopisch Lane,Director of Sales,41
33,Jacquenetta,Le Prevost,jleprevostw@netlog.com,Female,31 Le Prevost Trail,Senior Developer,47
34,Garvy,Rusted,grustedx@aboutads.info,Male,32 Rusted Junction,Senior Developer,42
35,Clarice,Aysh,cayshy@merriam-webster.com,Female,33 Aysh Avenue,VP Quality Control,40
36,Tracie,Fedorski,tfedorskiz@bloglines.com,Male,34 Fedorski Terrace,Design Engineer,44
37,Noelyn,Matushenko,nmatushenko10@globo.com,Female,35 Matushenko Place,VP Sales,48
38,Rudiger,Klaesson,rklaesson11@usnews.com,Male,36 Klaesson Road,Database Administrator IV,43
39,Mirella,Syddie,msyddie12@geocities.jp,Female,37 Syddie Circle,Geological Engineer,46
40,Donalt,O'Lunny,dolunny13@elpais.com,Male,38 O'Lunny Center,Analog Circuit Design manager,41
41,Guntar,Deniskevich,gdeniskevich14@google.com.hk,Male,39 Deniskevich Way,Structural Engineer,47
42,Hort,Shufflebotham,hshufflebotham15@about.me,Male,40 Shufflebotham Court,Structural Analysis Engineer,45
43,Dominique,Thickett,dthickett16@slashdot.org,Male,41 Thickett Crossing,Safety Technician I,42
44,Zebulen,Piscopello,zpiscopello17@umich.edu,Male,42 Piscopello Parkway,Web Developer II,40
45,Mellicent,Mac Giany,mmacgiany18@state.tx.us,Female,43 Mac Giany Pass,Assistant Manager,44
46,Merle,Bounds,mbounds19@amazon.co.jp,Female,44 Bounds Alley,Systems Administrator III,41
47,Madelle,Farbrace,mfarbrace1a@xinhuanet.com,Female,45 Farbrace Terrace,Quality Engineer,48
48,Galvin,O'Sheeryne,gosheeryne1b@addtoany.com,Male,46 O'Sheeryne Way,Environmental Specialist,43
49,Guillemette,Bootherstone,gbootherstone1c@nationalgeographic.com,Female,47 Bootherstone Plaza,Professor,46
50,Letti,Aylmore,laylmore1d@vinaora.com,Female,48 Aylmore Circle,Automation Specialist I,40
51,Nonie,Rivalland,nrivalland1e@weather.com,Female,49 Rivalland Avenue,Software Test Engineer IV,45
52,Jacquelynn,Halfacre,jhalfacre1f@surveymonkey.com,Female,50 Halfacre Pass,Geologist II,42
53,Anderea,MacKibbon,amackibbon1g@weibo.com,Female,51 MacKibbon Parkway,Automation Specialist II,47
54,Wash,Klimko,wklimko1h@slashdot.org,Male,52 Klimko Alley,Database Administrator I,40
55,Flori,Kynett,fkynett1i@auda.org.au,Female,53 Kynett Trail,Quality Control Specialist,46
56,Libbey,Penswick,lpenswick1j@google.co.uk,Female,54 Penswick Point,VP Accounting,43
57,Silvanus,Skellorne,sskellorne1k@booking.com,Male,55 Skellorne Drive,Account Executive,48
58,Carmine,Mateos,cmateos1l@plala.or.jp,Male,56 Mateos Terrace,Systems Administrator I,41
59,Sheffie,Blazewicz,sblazewicz1m@google.com.au,Male,57 Blazewicz Center,VP Sales,44
60,Leanor,Worsnop,lworsnop1n@uol.com.br,Female,58 Worsnop Plaza,Systems Administrator III,45
61,Caspar,Pamment,cpamment1o@google.co.jp,Male,59 Pamment Court,Senior Financial Analyst,42
62,Justinian,Pentycost,jpentycost1p@sciencedaily.com,Male,60 Pentycost Way,Senior Quality Engineer,47
63,Gerianne,Jarnell,gjarnell1q@bing.com,Female,61 Jarnell Avenue,Help Desk Operator,40
64,Boycie,Zanetto,bzanetto1r@about.com,Male,62 Zanetto Place,Quality Engineer,46
65,Camilla,Mac Giany,cmacgiany1s@state.gov,Female,63 Mac Giany Parkway,Senior Cost Accountant,43
66,Hadlee,Piscopiello,hpiscopiello1t@artisteer.com,Male,64 Piscopiello Street,Account Representative III,48
67,Bobbie,Penvarden,bpenvarden1u@google.cn,Male,65 Penvarden Lane,Help Desk Operator,41
68,Ali,Gowlett,agowlett1v@parallels.com,Male,66 Gowlett Pass,VP Marketing,44
69,Olivette,Acome,oacome1w@qq.com,Female,67 Acome Hill,VP Product Management,45
70,Jehanna,Brotherheed,jbrotherheed1x@google.nl,Female,68 Brotherheed Junction,Database Administrator III,42
71,Morgan,Berthomieu,mberthomieu1y@artisteer.com,Male,69 Berthomieu Alley,Systems Administrator II,47
72,Linzy,Shilladay,lshilladay1z@icq.com,Female,70 Shilladay Trail,Research Assistant IV,40
73,Faydra,Brimner,fbrimner20@mozilla.org,Female,71 Brimner Road,Senior Editor,46
74,Gwenore,Oxlee,goxlee21@devhub.com,Female,72 Oxlee Terrace,Systems Administrator II,43
75,Evangelin,Beinke,ebeinke22@mozilla.com,Female,73 Beinke Circle,Accountant I,48
76,Missy,Cockling,mcockling23@si.edu,Female,74 Cockling Way,Software Engineer I,41
77,Suzanne,Klimschak,sklimschak24@etsy.com,Female,75 Klimschak Plaza,Tax Accountant,44
78,Candide,Goricke,cgoricke25@weebly.com,Female,76 Goricke Pass,Sales Associate,45
79,Gerome,Pinsent,gpinsent26@google.com.au,Male,77 Pinsent Junction,Software Consultant,42
80,Lezley,Mac Giany,lmacgiany27@scribd.com,Male,78 Mac Giany Alley,Operator,47
81,Tobiah,Durn,tdurn28@state.tx.us,Male,79 Durn Court,VP Sales,40
82,Sherlocke,Cockshoot,scockshoot29@yelp.com,Male,80 Cockshoot Street,Senior Financial Analyst,46
83,Myrle,Speenden,mspeenden2a@utexas.edu,Female,81 Speenden Center,Senior Developer,43
84,Isidore,Gorries,igorries2b@flavors.me,Male,82 Gorries Parkway,Sales Representative,48
85,Isac,Kitchingman,ikitchingman2c@businessinsider.com,Male,83 Kitchingman Drive,VP Accounting,41
86,Benedetta,Purrier,bpurrier2d@admin.ch,Female,84 Purrier Trail,VP Accounting,44
87,Tera,Fitchell,tfitchell2e@fotki.com,Female,85 Fitchell Place,Software Engineer IV,45
88,Abbe,Pamment,apamment2f@about.com,Male,86 Pamment Avenue,VP Sales,42
89,Jandy,Gommowe,jgommowe2g@angelfire.com,Female,87 Gommowe Road,Financial Analyst,47
90,Karena,Fussey,kfussey2h@google.com.au,Female,88 Fussey Point,Assistant Professor,40
91,Gaspar,Pammenter,gpammenter2i@google.com.br,Male,89 Pammenter Hill,Help Desk Operator,46
92,Stanwood,Mac Giany,smacgiany2j@prlog.org,Male,90 Mac Giany Terrace,Research Associate,43
93,Byrom,Beedell,bbeedell2k@google.co.jp,Male,91 Beedell Way,VP Sales,48
94,Annabella,Rowbottom,arowbottom2l@google.com.au,Female,92 Rowbottom Plaza,Help Desk Operator,41
95,Rodolphe,Debell,rdebell2m@imageshack.us,Male,93 Debell Pass,Design Engineer,44
96,Tyne,Gommey,tgommey2n@joomla.org,Female,94 Gommey Junction,VP Marketing,45
97,Christoper,Pincked,cpincked2o@icq.com,Male,95 Pincked Alley,Human Resources Manager,42
98,Kore,Le Prevost,kleprevost2p@tripadvisor.com,Female,96 Le Prevost Street,VP Quality Control,47
99,Ceciley,Petrolli,cpetrolli2q@oaic.gov.au,Female,97 Petrolli Court,Senior Developer,40
100,Elspeth,Mac Giany,emacgiany2r@icio.us,Female,98 Mac Giany Parkway,Internal Auditor,46
""";
/**
* Initializes the service after dependency injection by loading data from the CSV string.
* Uses @PostConstruct to ensure this runs after the bean is created.
*/
@PostConstruct
private void initializeData() {
log.info("Initializing PersonService data store...");
int maxId = loadDataFromCsv();
idGenerator = new AtomicInteger(maxId);
log.info("PersonService initialized with {} records. Next ID: {}", personStore.size(), idGenerator.get() + 1);
}
/**
* Parses the embedded CSV data and populates the in-memory store.
* Calculates the maximum ID found in the data to initialize the ID generator.
*
* @return The maximum ID found in the loaded CSV data.
*/
private int loadDataFromCsv() {
final AtomicInteger currentMaxId = new AtomicInteger(0);
// Clear existing data before loading (important for tests or re-initialization scenarios)
personStore.clear();
try (Stream<String> lines = CSV_DATA.lines().skip(1)) { // Skip header row
lines.forEach(line -> {
try {
// Split carefully, handling potential commas within quoted fields if necessary (simple split here)
String[] fields = line.split(",", 8); // Limit split to handle potential commas in job title
if (fields.length == 8) {
int id = Integer.parseInt(fields[0].trim());
String firstName = fields[1].trim();
String lastName = fields[2].trim();
String email = fields[3].trim();
String sex = fields[4].trim();
String ipAddress = fields[5].trim();
String jobTitle = fields[6].trim();
int age = Integer.parseInt(fields[7].trim());
Person person = new Person(id, firstName, lastName, email, sex, ipAddress, jobTitle, age);
personStore.put(id, person);
currentMaxId.updateAndGet(max -> Math.max(max, id));
} else {
log.warn("Skipping malformed CSV line (expected 8 fields, found {}): {}", fields.length, line);
}
} catch (NumberFormatException e) {
log.warn("Skipping line due to parsing error (ID or Age): {} - Error: {}", line, e.getMessage());
} catch (Exception e) {
log.error("Skipping line due to unexpected error: {} - Error: {}", line, e.getMessage(), e);
}
});
} catch (Exception e) {
log.error("Fatal error reading embedded CSV data: {}", e.getMessage(), e);
// In a real application, might throw a specific initialization exception
}
return currentMaxId.get();
}
@Override
@Tool(
name = "ps_create_person",
description = "Create a new person record in the in-memory store."
)
public Person createPerson(Person personData) {
if (personData == null) {
throw new IllegalArgumentException("Person data cannot be null");
}
int newId = idGenerator.incrementAndGet();
// Create a new Person record using data from the input, but with the generated ID
Person newPerson = new Person(
newId,
personData.firstName(),
personData.lastName(),
personData.email(),
personData.sex(),
personData.ipAddress(),
personData.jobTitle(),
personData.age()
);
personStore.put(newId, newPerson);
log.debug("Created person: {}", newPerson);
return newPerson;
}
@Override
@Tool(
name = "ps_get_person_by_id",
description = "Retrieve a person record by ID from the in-memory store."
)
public Optional<Person> getPersonById(int id) {
Person person = personStore.get(id);
log.debug("Retrieved person by ID {}: {}", id, person);
return Optional.ofNullable(person);
}
@Override
@Tool(
name = "ps_get_all_persons",
description = "Retrieve all person records from the in-memory store."
)
public List<Person> getAllPersons() {
// Return an unmodifiable view of the values
List<Person> allPersons = personStore.values().stream().toList();
log.debug("Retrieved all persons (count: {})", allPersons.size());
return allPersons;
}
@Override
@Tool(
name = "ps_update_person",
description = "Update an existing person record by ID in the in-memory store."
)
public boolean updatePerson(int id, Person updatedPersonData) {
if (updatedPersonData == null) {
throw new IllegalArgumentException("Updated person data cannot be null");
}
// Use computeIfPresent for atomic update if the key exists
Person result = personStore.computeIfPresent(id, (key, existingPerson) ->
// Create a new Person record with the original ID but updated data
new Person(
id, // Keep original ID
updatedPersonData.firstName(),
updatedPersonData.lastName(),
updatedPersonData.email(),
updatedPersonData.sex(),
updatedPersonData.ipAddress(),
updatedPersonData.jobTitle(),
updatedPersonData.age()
)
);
boolean updated = result != null;
log.debug("Update attempt for ID {}: {}", id, updated ? "Successful" : "Failed (Not Found)");
if(updated) log.trace("Updated person data for ID {}: {}", id, result);
return updated;
}
@Override
@Tool(
name = "ps_delete_person",
description = "Delete a person record by ID from the in-memory store."
)
public boolean deletePerson(int id) {
boolean removed = personStore.remove(id) != null;
log.debug("Delete attempt for ID {}: {}", id, removed ? "Successful" : "Failed (Not Found)");
return removed;
}
@Override
@Tool(
name = "ps_search_by_job_title",
description = "Search for persons by job title in the in-memory store."
)
public List<Person> searchByJobTitle(String jobTitleQuery) {
if (jobTitleQuery == null || jobTitleQuery.isBlank()) {
log.debug("Search by job title skipped due to blank query.");
return Collections.emptyList();
}
String lowerCaseQuery = jobTitleQuery.toLowerCase();
List<Person> results = personStore.values().stream()
.filter(person -> person.jobTitle() != null && person.jobTitle().toLowerCase().contains(lowerCaseQuery))
.collect(Collectors.toList());
log.debug("Search by job title '{}' found {} results.", jobTitleQuery, results.size());
return Collections.unmodifiableList(results);
}
@Override
@Tool(
name = "ps_filter_by_sex",
description = "Filters Persons by sex (case-insensitive)."
)
public List<Person> filterBySex(String sex) {
if (sex == null || sex.isBlank()) {
log.debug("Filter by sex skipped due to blank filter.");
return Collections.emptyList();
}
List<Person> results = personStore.values().stream()
.filter(person -> person.sex() != null && person.sex().equalsIgnoreCase(sex))
.collect(Collectors.toList());
log.debug("Filter by sex '{}' found {} results.", sex, results.size());
return Collections.unmodifiableList(results);
}
@Override
@Tool(
name = "ps_filter_by_age",
description = "Filters Persons by age."
)
public List<Person> filterByAge(int age) {
if (age < 0) {
log.debug("Filter by age skipped due to negative age: {}", age);
return Collections.emptyList(); // Or throw IllegalArgumentException based on requirements
}
List<Person> results = personStore.values().stream()
.filter(person -> person.age() == age)
.collect(Collectors.toList());
log.debug("Filter by age {} found {} results.", age, results.size());
return Collections.unmodifiableList(results);
}
}

View File

@ -0,0 +1,4 @@
/**
* 参考 <a href="https://docs.spring.io/spring-ai/reference/api/tools.html#_methods_as_tools">Tool Calling Methods as Tools</a>
*/
package cn.iocoder.yudao.module.ai.tool.method;

View File

@ -8,18 +8,20 @@ import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import org.springaicommunity.moonshot.MoonshotChatOptions;
import org.springaicommunity.qianfan.QianFanChatOptions;
import org.springframework.ai.anthropic.AnthropicChatOptions;
import org.springframework.ai.azure.openai.AzureOpenAiChatOptions;
import org.springframework.ai.chat.messages.*;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.deepseek.DeepSeekAssistantMessage;
import org.springframework.ai.deepseek.DeepSeekChatOptions;
import org.springframework.ai.minimax.MiniMaxChatOptions;
import org.springframework.ai.ollama.api.OllamaOptions;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.zhipuai.ZhiPuAiChatOptions;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.*;
/**
* Spring AI 工具类
@ -36,40 +38,47 @@ public class AiUtils {
}
public static ChatOptions buildChatOptions(AiPlatformEnum platform, String model, Double temperature, Integer maxTokens,
Set<String> toolNames, Map<String, Object> toolContext) {
toolNames = ObjUtil.defaultIfNull(toolNames, Collections.emptySet());
List<ToolCallback> toolCallbacks, Map<String, Object> toolContext) {
toolCallbacks = ObjUtil.defaultIfNull(toolCallbacks, Collections.emptyList());
toolContext = ObjUtil.defaultIfNull(toolContext, Collections.emptyMap());
// noinspection EnhancedSwitchMigration
switch (platform) {
case TONG_YI:
return DashScopeChatOptions.builder().withModel(model).withTemperature(temperature).withMaxToken(maxTokens)
.withToolNames(toolNames).withToolContext(toolContext).build();
.withEnableThinking(true) // TODO 芋艿默认都开启 thinking 模式后续可以让用户配置
.withToolCallbacks(toolCallbacks).withToolContext(toolContext).build();
case YI_YAN:
return QianFanChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens).build();
case DEEP_SEEK:
case DOU_BAO: // 复用 DeepSeek 客户端
case HUN_YUAN: // 复用 DeepSeek 客户端
case SILICON_FLOW: // 复用 DeepSeek 客户端
case XING_HUO: // 复用 DeepSeek 客户端
return DeepSeekChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
.toolCallbacks(toolCallbacks).toolContext(toolContext).build();
case ZHI_PU:
return ZhiPuAiChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
.toolNames(toolNames).toolContext(toolContext).build();
.toolCallbacks(toolCallbacks).toolContext(toolContext).build();
case MINI_MAX:
return MiniMaxChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
.toolNames(toolNames).toolContext(toolContext).build();
.toolCallbacks(toolCallbacks).toolContext(toolContext).build();
case MOONSHOT:
return MoonshotChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
.toolNames(toolNames).toolContext(toolContext).build();
.toolCallbacks(toolCallbacks).toolContext(toolContext).build();
case OPENAI:
case DEEP_SEEK: // 复用 OpenAI 客户端
case DOU_BAO: // 复用 OpenAI 客户端
case HUN_YUAN: // 复用 OpenAI 客户端
case XING_HUO: // 复用 OpenAI 客户端
case SILICON_FLOW: // 复用 OpenAI 客户端
case GEMINI: // 复用 OpenAI 客户端
case BAI_CHUAN: // 复用 OpenAI 客户端
return OpenAiChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
.toolNames(toolNames).toolContext(toolContext).build();
.toolCallbacks(toolCallbacks).toolContext(toolContext).build();
case AZURE_OPENAI:
return AzureOpenAiChatOptions.builder().deploymentName(model).temperature(temperature).maxTokens(maxTokens)
.toolNames(toolNames).toolContext(toolContext).build();
.toolCallbacks(toolCallbacks).toolContext(toolContext).build();
case ANTHROPIC:
return AnthropicChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
.toolCallbacks(toolCallbacks).toolContext(toolContext).build();
case OLLAMA:
return OllamaOptions.builder().model(model).temperature(temperature).numPredict(maxTokens)
.toolNames(toolNames).toolContext(toolContext).build();
.toolCallbacks(toolCallbacks).toolContext(toolContext).build();
default:
throw new IllegalArgumentException(StrUtil.format("未知平台({})", platform));
}
@ -98,4 +107,27 @@ public class AiUtils {
return context;
}
@SuppressWarnings("ConstantValue")
public static String getChatResponseContent(ChatResponse response) {
if (response == null
|| response.getResult() == null
|| response.getResult().getOutput() == null) {
return null;
}
return response.getResult().getOutput().getText();
}
@SuppressWarnings("ConstantValue")
public static String getChatResponseReasoningContent(ChatResponse response) {
if (response == null
|| response.getResult() == null
|| response.getResult().getOutput() == null) {
return null;
}
if (response.getResult().getOutput() instanceof DeepSeekAssistantMessage) {
return ((DeepSeekAssistantMessage) (response.getResult().getOutput())).getReasoningContent();
}
return null;
}
}

View File

@ -0,0 +1,37 @@
package cn.iocoder.yudao.module.ai.util;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.tika.Tika;
/**
* 文件类型 Utils
*
* @author 芋道源码
*/
@Slf4j
public class FileTypeUtils {
private static final Tika TIKA = new Tika();
/**
* 已知文件名获取文件类型在某些情况下比通过字节数组准确例如使用 jar 文件时通过名字更为准确
*
* @param name 文件名
* @return mineType 无法识别时会返回application/octet-stream
*/
public static String getMineType(String name) {
return TIKA.detect(name);
}
/**
* 判断是否是图片
*
* @param mineType 类型
* @return 是否是图片
*/
public static boolean isImage(String mineType) {
return StrUtil.startWith(mineType, "image/");
}
}

View File

@ -0,0 +1,87 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.ai.anthropic.AnthropicChatModel;
import org.springframework.ai.anthropic.AnthropicChatOptions;
import org.springframework.ai.anthropic.api.AnthropicApi;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
import java.util.List;
/**
* {@link AnthropicChatModel} 集成测试类
*
* @author 芋道源码
*/
public class AnthropicChatModelTest {
private final AnthropicChatModel chatModel = AnthropicChatModel.builder()
.anthropicApi(AnthropicApi.builder()
.apiKey("sk-muubv7cXeLw0Etgs743f365cD5Ea44429946Fa7e672d8942")
.baseUrl("https://aihubmix.com")
.build())
.defaultOptions(AnthropicChatOptions.builder()
.model(AnthropicApi.ChatModel.CLAUDE_SONNET_4)
.temperature(0.7)
.maxTokens(4096)
.build())
.build();
@Test
@Disabled
public void testCall() {
// 准备参数
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
messages.add(new UserMessage("1 + 1 = "));
// 调用
ChatResponse response = chatModel.call(new Prompt(messages));
// 打印结果
System.out.println(response);
}
@Test
@Disabled
public void testStream() {
// 准备参数
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
messages.add(new UserMessage("1 + 1 = "));
// 调用
Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages));
// 打印结果
flux.doOnNext(System.out::println).then().block();
}
// TODO @芋艿需要等 spring ai 升级https://github.com/spring-projects/spring-ai/pull/2800
@Test
@Disabled
public void testStream_thinking() {
// 准备参数
List<Message> messages = new ArrayList<>();
messages.add(new UserMessage("thkinking 下1+1 为什么等于 2 "));
AnthropicChatOptions options = AnthropicChatOptions.builder()
.model(AnthropicApi.ChatModel.CLAUDE_SONNET_4)
.thinking(AnthropicApi.ThinkingType.ENABLED, 3096)
.temperature(1D)
.build();
// 调用
Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages, options));
// 打印结果
flux.doOnNext(response -> {
// System.out.println(response);
System.out.println(response.getResult());
}).then().block();
}
}

View File

@ -60,4 +60,23 @@ public class DeepSeekChatModelTests {
flux.doOnNext(System.out::println).then().block();
}
@Test
@Disabled
public void testStream_thinking() {
// 准备参数
List<Message> messages = new ArrayList<>();
messages.add(new UserMessage("详细分析下,如何设计一个电商系统?"));
DeepSeekChatOptions options = DeepSeekChatOptions.builder()
.model("deepseek-reasoner")
.build();
// 调用
Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages, options));
// 打印结果
flux.doOnNext(response -> {
// System.out.println(response);
System.out.println(response.getResult().getOutput());
}).then().block();
}
}

View File

@ -8,9 +8,9 @@ import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.deepseek.DeepSeekChatModel;
import org.springframework.ai.deepseek.DeepSeekChatOptions;
import org.springframework.ai.deepseek.api.DeepSeekApi;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
@ -23,13 +23,18 @@ import java.util.List;
*/
public class DouBaoChatModelTests {
private final OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
.openAiApi(OpenAiApi.builder()
/**
* 相比 OpenAIChatModel 来说DeepSeekChatModel 可以兼容豆包的 thinking 能力
*/
private final DeepSeekChatModel openAiChatModel = DeepSeekChatModel.builder()
.deepSeekApi(DeepSeekApi.builder()
.baseUrl(DouBaoChatModel.BASE_URL)
.completionsPath(DouBaoChatModel.COMPLETE_PATH)
.apiKey("5c1b5747-26d2-4ebd-a4e0-dd0e8d8b4272") // apiKey
.build())
.defaultOptions(OpenAiChatOptions.builder()
.defaultOptions(DeepSeekChatOptions.builder()
.model("doubao-1-5-lite-32k-250115") // 模型doubao
// .model("doubao-seed-1-6-thinking-250715") // 模型doubao
// .model("deepseek-r1-250120") // 模型deepseek
.temperature(0.7)
.build())
@ -51,14 +56,13 @@ public class DouBaoChatModelTests {
System.out.println(response);
}
// TODO @芋艿因为使用的是 v1 api导致 deepseek-r1-250120 不返回 think 过程后续需要优化
@Test
@Disabled
public void testStream() {
// 准备参数
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
messages.add(new UserMessage("1 + 1 = "));
messages.add(new UserMessage("详细推理下,帮我设计一个用户中心!"));
// 调用
Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages));
@ -66,4 +70,23 @@ public class DouBaoChatModelTests {
flux.doOnNext(System.out::println).then().block();
}
@Test
@Disabled
public void testStream_thinking() {
// 准备参数
List<Message> messages = new ArrayList<>();
messages.add(new UserMessage("详细分析下,如何设计一个电商系统?"));
DeepSeekChatOptions options = DeepSeekChatOptions.builder()
.model("doubao-seed-1-6-thinking-250715")
.build();
// 调用
Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages, options));
// 打印结果
flux.doOnNext(response -> {
// System.out.println(response);
System.out.println(response.getResult().getOutput());
}).then().block();
}
}

View File

@ -0,0 +1,68 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.gemini.GeminiChatModel;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.openai.api.OpenAiApi;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
import java.util.List;
/**
* {@link GeminiChatModel} 集成测试
*
* @author 芋道源码
*/
public class GeminiChatModelTests {
private final OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
.openAiApi(OpenAiApi.builder()
.baseUrl(GeminiChatModel.BASE_URL)
.completionsPath(GeminiChatModel.COMPLETE_PATH)
.apiKey("AIzaSyAVoBxgoFvvte820vEQMma2LKBnC98bqMQ")
.build())
.defaultOptions(OpenAiChatOptions.builder()
.model(GeminiChatModel.MODEL_DEFAULT) // 模型
.temperature(0.7)
.build())
.build();
private final GeminiChatModel chatModel = new GeminiChatModel(openAiChatModel);
@Test
@Disabled
public void testCall() {
// 准备参数
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
messages.add(new UserMessage("1 + 1 = "));
// 调用
ChatResponse response = chatModel.call(new Prompt(messages));
// 打印结果
System.out.println(response);
}
@Test
@Disabled
public void testStream() {
// 准备参数
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
messages.add(new UserMessage("1 + 1 = "));
// 调用
Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages));
// 打印结果
flux.doOnNext(System.out::println).then().block();
}
}

View File

@ -8,9 +8,9 @@ import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.deepseek.DeepSeekChatModel;
import org.springframework.ai.deepseek.DeepSeekChatOptions;
import org.springframework.ai.deepseek.api.DeepSeekApi;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
@ -23,12 +23,13 @@ import java.util.List;
*/
public class HunYuanChatModelTests {
private final OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
.openAiApi(OpenAiApi.builder()
private final DeepSeekChatModel openAiChatModel = DeepSeekChatModel.builder()
.deepSeekApi(DeepSeekApi.builder()
.baseUrl(HunYuanChatModel.BASE_URL)
.apiKey("sk-bcd") // apiKey
.completionsPath(HunYuanChatModel.COMPLETE_PATH)
.apiKey("sk-abc") // apiKey
.build())
.defaultOptions(OpenAiChatOptions.builder()
.defaultOptions(DeepSeekChatOptions.builder()
.model(HunYuanChatModel.MODEL_DEFAULT) // 模型
.temperature(0.7)
.build())
@ -64,12 +65,33 @@ public class HunYuanChatModelTests {
flux.doOnNext(System.out::println).then().block();
}
private final OpenAiChatModel deepSeekOpenAiChatModel = OpenAiChatModel.builder()
.openAiApi(OpenAiApi.builder()
@Test
@Disabled
public void testStream_thinking() {
// 准备参数
List<Message> messages = new ArrayList<>();
messages.add(new UserMessage("详细分析下,如何设计一个电商系统?"));
DeepSeekChatOptions options = DeepSeekChatOptions.builder()
.model("hunyuan-a13b")
// .model("hunyuan-turbos-latest")
.build();
// 调用
Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages, options));
// 打印结果
flux.doOnNext(response -> {
// System.out.println(response);
System.out.println(response.getResult().getOutput());
}).then().block();
}
private final DeepSeekChatModel deepSeekOpenAiChatModel = DeepSeekChatModel.builder()
.deepSeekApi(DeepSeekApi.builder()
.baseUrl(HunYuanChatModel.DEEP_SEEK_BASE_URL)
.completionsPath(HunYuanChatModel.COMPLETE_PATH)
.apiKey("sk-abc") // apiKey
.build())
.defaultOptions(OpenAiChatOptions.builder()
.defaultOptions(DeepSeekChatOptions.builder()
// .model(HunYuanChatModel.DEEP_SEEK_MODEL_DEFAULT) // 模型"deepseek-v3"
.model("deepseek-r1") // 模型"deepseek-r1"
.temperature(0.7)
@ -94,7 +116,7 @@ public class HunYuanChatModelTests {
@Test
@Disabled
public void testStream_deekseek() {
public void testStream_deepseek() {
// 准备参数
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
@ -106,5 +128,23 @@ public class HunYuanChatModelTests {
flux.doOnNext(System.out::println).then().block();
}
@Test
@Disabled
public void testStream_deepseek_thinking() {
// 准备参数
List<Message> messages = new ArrayList<>();
messages.add(new UserMessage("详细分析下,如何设计一个电商系统?"));
DeepSeekChatOptions options = DeepSeekChatOptions.builder()
.model("deepseek-r1")
.build();
// 调用
Flux<ChatResponse> flux = deepSeekChatModel.stream(new Prompt(messages, options));
// 打印结果
flux.doOnNext(response -> {
// System.out.println(response);
System.out.println(response.getResult().getOutput());
}).then().block();
}
}

View File

@ -1,6 +1,20 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.ai.ollama.api.OllamaApi;
import org.springframework.ai.ollama.api.OllamaModel;
import org.springframework.ai.ollama.api.OllamaOptions;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
import java.util.List;
/**
* {@link OllamaChatModel} 集成测试
@ -9,43 +23,65 @@ import org.springframework.ai.ollama.OllamaChatModel;
*/
public class LlamaChatModelTests {
// private final OllamaChatModel chatModel = OllamaChatModel.builder()
// .ollamaApi(new OllamaApi("http://127.0.0.1:11434")) // Ollama 服务地址
// .defaultOptions(OllamaOptions.builder()
// .model(OllamaModel.LLAMA3.getName()) // 模型
// .build())
// .build();
//
// @Test
// @Disabled
// public void testCall() {
// // 准备参数
// List<Message> messages = new ArrayList<>();
// messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
// messages.add(new UserMessage("1 + 1 = "));
//
// // 调用
// ChatResponse response = chatModel.call(new Prompt(messages));
// // 打印结果
// System.out.println(response);
// System.out.println(response.getResult().getOutput());
// }
//
// @Test
// @Disabled
// public void testStream() {
// // 准备参数
// List<Message> messages = new ArrayList<>();
// messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
// messages.add(new UserMessage("1 + 1 = "));
//
// // 调用
// Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages));
// // 打印结果
// flux.doOnNext(response -> {
//// System.out.println(response);
// System.out.println(response.getResult().getOutput());
// }).then().block();
// }
private final OllamaChatModel chatModel = OllamaChatModel.builder()
.ollamaApi(OllamaApi.builder()
.baseUrl("http://127.0.0.1:11434") // Ollama 服务地址
.build())
.defaultOptions(OllamaOptions.builder()
.model(OllamaModel.LLAMA3.getName()) // 模型
.build())
.build();
@Test
@Disabled
public void testCall() {
// 准备参数
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
messages.add(new UserMessage("1 + 1 = "));
// 调用
ChatResponse response = chatModel.call(new Prompt(messages));
// 打印结果
System.out.println(response);
System.out.println(response.getResult().getOutput());
}
@Test
@Disabled
public void testStream() {
// 准备参数
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
messages.add(new UserMessage("1 + 1 = "));
// 调用
Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages));
// 打印结果
flux.doOnNext(response -> {
// System.out.println(response);
System.out.println(response.getResult().getOutput());
}).then().block();
}
@Test
@Disabled
public void testStream_thinking() {
// 准备参数
List<Message> messages = new ArrayList<>();
messages.add(new UserMessage("详细分析下,如何设计一个电商系统?"));
OllamaOptions options = OllamaOptions.builder()
.model("qwen3")
.build();
// 调用
Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages, options));
// 打印结果
flux.doOnNext(response -> {
// System.out.println(response);
System.out.println(response.getResult().getOutput());
}).then().block();
}
}

View File

@ -59,4 +59,24 @@ public class MiniMaxChatModelTests {
}).then().block();
}
// TODO @芋艿暂时没解析 reasoning_content 结果需要等官方修复
@Test
@Disabled
public void testStream_thinking() {
// 准备参数
List<Message> messages = new ArrayList<>();
messages.add(new UserMessage("详细分析下,如何设计一个电商系统?"));
MiniMaxChatOptions options = MiniMaxChatOptions.builder()
.model("MiniMax-M1")
.build();
// 调用
Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages, options));
// 打印结果
flux.doOnNext(response -> {
// System.out.println(response);
System.out.println(response.getResult().getOutput());
}).then().block();
}
}

View File

@ -63,4 +63,25 @@ public class MoonshotChatModelTests {
}).then().block();
}
// TODO @芋艿暂时没解析 reasoning_content 结果需要等官方修复
@Test
@Disabled
public void testStream_thinking() {
// 准备参数
List<Message> messages = new ArrayList<>();
messages.add(new UserMessage("详细分析下,如何设计一个电商系统?"));
MoonshotChatOptions options = MoonshotChatOptions.builder()
// .model("kimi-k2-0711-preview")
.model("kimi-thinking-preview")
.build();
// 调用
Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages, options));
// 打印结果
flux.doOnNext(response -> {
// System.out.println(response);
System.out.println(response.getResult().getOutput());
}).then().block();
}
}

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
import com.azure.ai.openai.models.ReasoningEffortValue;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.messages.Message;
@ -25,10 +26,11 @@ public class OpenAIChatModelTests {
private final OpenAiChatModel chatModel = OpenAiChatModel.builder()
.openAiApi(OpenAiApi.builder()
.baseUrl("https://api.holdai.top")
.apiKey("sk-PytRecQlmjEteoa2RRN6cGnwslo72UUPLQVNEMS6K9yjbmpD") // apiKey
.apiKey("sk-z5joyRoV1iFEnh2SAi8QPNrIZTXyQSyxTmD5CoNDQbFixK2l") // apiKey
.build())
.defaultOptions(OpenAiChatOptions.builder()
.model(OpenAiApi.ChatModel.GPT_4_1_NANO) // 模型
.model("gpt-5-nano-2025-08-07") // 模型
// .model(OpenAiApi.ChatModel.O1) // 模型
.temperature(0.7)
.build())
.build();
@ -54,7 +56,7 @@ public class OpenAIChatModelTests {
// 准备参数
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
messages.add(new UserMessage("1 + 1 = "));
messages.add(new UserMessage("帮我推理下,怎么实现一个用户中心!"));
// 调用
Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages));
@ -65,4 +67,29 @@ public class OpenAIChatModelTests {
}).then().block();
}
// TODO @芋艿无法触发思考的字段返回需要 response apihttps://github.com/spring-projects/spring-ai/issues/2962
@Test
@Disabled
public void testStream_thinking() {
// 准备参数
List<Message> messages = new ArrayList<>();
messages.add(new UserMessage("详细分析下,如何设计一个电商系统?"));
OpenAiChatOptions options = OpenAiChatOptions.builder()
.model("gpt-5")
// .model(OpenAiApi.ChatModel.O4_MINI)
// .model("o3-pro")
.reasoningEffort(ReasoningEffortValue.LOW.getValue())
.build();
// 调用
Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages, options));
// 打印结果
flux.doOnNext(response -> {
// System.out.println(response);
System.out.println(response.getResult().getOutput());
}).then().block();
}
}

View File

@ -9,9 +9,9 @@ import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.deepseek.DeepSeekChatModel;
import org.springframework.ai.deepseek.DeepSeekChatOptions;
import org.springframework.ai.deepseek.api.DeepSeekApi;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
@ -24,12 +24,12 @@ import java.util.List;
*/
public class SiliconFlowChatModelTests {
private final OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
.openAiApi(OpenAiApi.builder()
private final DeepSeekChatModel openAiChatModel = DeepSeekChatModel.builder()
.deepSeekApi(DeepSeekApi.builder()
.baseUrl(SiliconFlowApiConstants.DEFAULT_BASE_URL)
.apiKey("sk-epsakfenqnyzoxhmbucsxlhkdqlcbnimslqoivkshalvdozz") // apiKey
.build())
.defaultOptions(OpenAiChatOptions.builder()
.defaultOptions(DeepSeekChatOptions.builder()
.model(SiliconFlowApiConstants.MODEL_DEFAULT) // 模型
// .model("deepseek-ai/DeepSeek-R1") // 模型deepseek-ai/DeepSeek-R1可用赠费
// .model("Pro/deepseek-ai/DeepSeek-R1") // 模型Pro/deepseek-ai/DeepSeek-R1需要付费
@ -67,4 +67,23 @@ public class SiliconFlowChatModelTests {
flux.doOnNext(System.out::println).then().block();
}
@Test
@Disabled
public void testStream_thinking() {
// 准备参数
List<Message> messages = new ArrayList<>();
messages.add(new UserMessage("详细分析下,如何设计一个电商系统?"));
DeepSeekChatOptions options = DeepSeekChatOptions.builder()
.model("deepseek-ai/DeepSeek-R1")
.build();
// 调用
Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages, options));
// 打印结果
flux.doOnNext(response -> {
// System.out.println(response);
System.out.println(response.getResult().getOutput());
}).then().block();
}
}

View File

@ -1,8 +1,15 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import com.alibaba.cloud.ai.dashscope.rerank.DashScopeRerankModel;
import com.alibaba.cloud.ai.dashscope.rerank.DashScopeRerankOptions;
import com.alibaba.cloud.ai.model.RerankModel;
import com.alibaba.cloud.ai.model.RerankOptions;
import com.alibaba.cloud.ai.model.RerankRequest;
import com.alibaba.cloud.ai.model.RerankResponse;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.messages.Message;
@ -10,11 +17,14 @@ import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.document.Document;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
import java.util.List;
import static java.util.Arrays.asList;
/**
* {@link DashScopeChatModel} 集成测试类
*
@ -26,11 +36,13 @@ public class TongYiChatModelTests {
.dashScopeApi(DashScopeApi.builder()
.apiKey("sk-47aa124781be4bfb95244cc62f63f7d0")
.build())
.defaultOptions( DashScopeChatOptions.builder()
.withModel("qwen1.5-72b-chat") // 模型
.defaultOptions(DashScopeChatOptions.builder()
// .withModel("qwen1.5-72b-chat") // 模型
.withModel("qwen3-235b-a22b-thinking-2507") // 模型
// .withModel("deepseek-r1") // 模型deepseek-r1
// .withModel("deepseek-v3") // 模型deepseek-v3
// .withModel("deepseek-r1-distill-qwen-1.5b") // 模型deepseek-r1-distill-qwen-1.5b
// .withEnableThinking(true)
.build())
.build();
@ -54,8 +66,8 @@ public class TongYiChatModelTests {
public void testStream() {
// 准备参数
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
messages.add(new UserMessage("1 + 1 = "));
// messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
messages.add(new UserMessage("帮我推理下,怎么实现一个用户中心!"));
// 调用
Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages));
@ -66,4 +78,52 @@ public class TongYiChatModelTests {
}).then().block();
}
@Test
@Disabled
public void testStream_thinking() {
// 准备参数
List<Message> messages = new ArrayList<>();
messages.add(new UserMessage("详细分析下,如何设计一个电商系统?"));
DashScopeChatOptions options = DashScopeChatOptions.builder()
.withModel("qwen3-235b-a22b-thinking-2507")
// .withModel("qwen-max-2025-01-25")
.withEnableThinking(true) // 必须设置否则会报错
.build();
// 调用
Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages, options));
// 打印结果
flux.doOnNext(response -> {
// System.out.println(response);
System.out.println(response.getResult().getOutput());
}).then().block();
}
@Test
@Disabled
public void testRerank() {
// 准备环境
RerankModel rerankModel = new DashScopeRerankModel(
DashScopeApi.builder()
.apiKey("sk-47aa124781be4bfb95244cc62f63f7d0")
.build());
// 准备参数
String query = "spring";
Document document01 = new Document("abc");
Document document02 = new Document("sapring");
RerankOptions options = DashScopeRerankOptions.builder()
.withTopN(1)
.withModel("gte-rerank-v2")
.build();
RerankRequest rerankRequest = new RerankRequest(
query,
asList(document01, document02),
options);
// 调用
RerankResponse call = rerankModel.call(rerankRequest);
// 打印结果
System.out.println(JsonUtils.toJsonPrettyString(call));
}
}

View File

@ -8,9 +8,9 @@ import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.deepseek.DeepSeekChatModel;
import org.springframework.ai.deepseek.DeepSeekChatOptions;
import org.springframework.ai.deepseek.api.DeepSeekApi;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
@ -23,13 +23,15 @@ import java.util.List;
*/
public class XingHuoChatModelTests {
private final OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
.openAiApi(OpenAiApi.builder()
.baseUrl(XingHuoChatModel.BASE_URL)
private final DeepSeekChatModel openAiChatModel = DeepSeekChatModel.builder()
.deepSeekApi(DeepSeekApi.builder()
.baseUrl(XingHuoChatModel.BASE_URL_V2)
.completionsPath(XingHuoChatModel.BASE_COMPLETIONS_PATH_V2)
.apiKey("75b161ed2aef4719b275d6e7f2a4d4cd:YWYxYWI2MTA4ODI2NGZlYTQyNjAzZTcz") // appKey:secretKey
.build())
.defaultOptions(OpenAiChatOptions.builder()
.model("generalv3.5") // 模型
.defaultOptions(DeepSeekChatOptions.builder()
// .model("generalv3.5") // 模型
.model("x1") // 模型
.temperature(0.7)
.build())
.build();
@ -64,4 +66,23 @@ public class XingHuoChatModelTests {
flux.doOnNext(System.out::println).then().block();
}
@Test
@Disabled
public void testStream_thinking() {
// 准备参数
List<Message> messages = new ArrayList<>();
messages.add(new UserMessage("详细分析下,如何设计一个电商系统?"));
DeepSeekChatOptions options = DeepSeekChatOptions.builder()
.model("x1")
.build();
// 调用
Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages, options));
// 打印结果
flux.doOnNext(response -> {
// System.out.println(response);
System.out.println(response.getResult().getOutput());
}).then().block();
}
}

View File

@ -23,7 +23,7 @@ import java.util.List;
public class ZhiPuAiChatModelTests {
private final ZhiPuAiChatModel chatModel = new ZhiPuAiChatModel(
new ZhiPuAiApi("32f84543e54eee31f8d56b2bd6020573.3vh9idLJZ2ZhxDEs"), // 密钥
new ZhiPuAiApi("2f35fb6ca4ea41fab898729b7fac086c.6ESSfPcCkxaKEUlR"), // 密钥
ZhiPuAiChatOptions.builder()
.model(ZhiPuAiApi.ChatModel.GLM_4.getName()) // 模型
.build()
@ -61,4 +61,24 @@ public class ZhiPuAiChatModelTests {
}).then().block();
}
// TODO @芋艿暂时没解析 reasoning_content 结果需要等官方修复
@Test
@Disabled
public void testStream_thinking() {
// 准备参数
List<Message> messages = new ArrayList<>();
messages.add(new UserMessage("详细分析下,如何设计一个电商系统?"));
ZhiPuAiChatOptions options = ZhiPuAiChatOptions.builder()
.model("GLM-4.5")
.build();
// 调用
Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages, options));
// 打印结果
flux.doOnNext(response -> {
// System.out.println(response);
System.out.println(response.getResult().getOutput());
}).then().block();
}
}

View File

@ -16,8 +16,11 @@ import org.springframework.ai.image.ImageResponse;
*/
public class TongYiImagesModelTest {
private final DashScopeImageModel imageModel = new DashScopeImageModel(
new DashScopeImageApi("sk-7d903764249848cfa912733146da12d1"));
private final DashScopeImageModel imageModel = DashScopeImageModel.builder()
.dashScopeApi(DashScopeImageApi.builder()
.apiKey("sk-47aa124781be4bfb95244cc62f63f7d0")
.build())
.build();
@Test
@Disabled

View File

@ -36,44 +36,47 @@ public class DouBaoMcpTests {
@Test
public void testMcpGetUserInfo() {
// 打印结果
System.out.println(chatClient.prompt()
.user("目前有哪些工具可以使用")
.call()
.content());
System.out.println("====================================");
// 打印结果
System.out.println(chatClient.prompt()
.user("小新的年龄是多少")
.call()
.content());
System.out.println("====================================");
// 打印结果
System.out.println(chatClient.prompt()
.user("获取小新的基本信息")
.call()
.content());
System.out.println("====================================");
// 打印结果
System.out.println(chatClient.prompt()
.user("小新是什么职业的")
.call()
.content());
System.out.println("====================================");
// 打印结果
System.out.println(chatClient.prompt()
.user("小新的教育背景")
.call()
.content());
System.out.println("====================================");
// 打印结果
System.out.println(chatClient.prompt()
.user("小新的兴趣爱好是什么")
.call()
.content());
System.out.println("====================================");
}

View File

@ -0,0 +1,28 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.websearch;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.module.ai.framework.ai.core.webserch.AiWebSearchRequest;
import cn.iocoder.yudao.module.ai.framework.ai.core.webserch.AiWebSearchResponse;
import cn.iocoder.yudao.module.ai.framework.ai.core.webserch.bocha.AiBoChaWebSearchClient;
import org.junit.jupiter.api.Test;
/**
* {@link AiBoChaWebSearchClient} 集成测试类
*
* @author 芋道源码
*/
public class AiBoChaWebSearchClientTest {
private final AiBoChaWebSearchClient webSearchClient = new AiBoChaWebSearchClient(
"sk-40500e52840f4d24b956d0b1d80d9abe");
@Test
public void testSearch() {
AiWebSearchRequest request = new AiWebSearchRequest()
.setQuery("阿里巴巴")
.setCount(3);
AiWebSearchResponse response = webSearchClient.search(request);
System.out.println(JsonUtils.toJsonPrettyString(response));
}
}

View File

@ -28,6 +28,11 @@ public class BpmProcessInstanceStatusEvent extends ApplicationEvent {
*/
@NotNull(message = "流程实例的状态不能为空")
private Integer status;
/**
* 流程实例结束的原因
*/
private String reason;
/**
* 流程实例对应的业务标识
* 例如说请假

View File

@ -119,8 +119,9 @@ public interface BpmProcessInstanceConvert {
@Mapping(source = "from.id", target = "to.id", ignore = true)
void copyTo(BpmProcessDefinitionInfoDO from, @MappingTarget BpmProcessDefinitionRespVO to);
default BpmProcessInstanceStatusEvent buildProcessInstanceStatusEvent(Object source, ProcessInstance instance, Integer status) {
return new BpmProcessInstanceStatusEvent(source).setId(instance.getId()).setStatus(status)
default BpmProcessInstanceStatusEvent buildProcessInstanceStatusEvent(Object source, ProcessInstance instance,
Integer status, String reason) {
return new BpmProcessInstanceStatusEvent(source).setId(instance.getId()).setStatus(status).setReason(reason)
.setProcessDefinitionKey(instance.getProcessDefinitionKey()).setBusinessKey(instance.getBusinessKey());
}

View File

@ -19,6 +19,7 @@ public enum BpmReasonEnum {
CANCEL_PROCESS_INSTANCE_BY_START_USER("用户主动取消流程,原因:{}"), // 场景用户主动取消流程
CANCEL_PROCESS_INSTANCE_BY_ADMIN("管理员【{}】取消流程,原因:{}"), // 场景管理员取消流程
CANCEL_CHILD_PROCESS_INSTANCE_BY_MAIN_PROCESS("子流程自动取消,原因:主流程已取消"),
REJECT_CHILD_PROCESS("子流程审批不通过"),
// ========== 流程任务的独有原因 ==========

View File

@ -52,6 +52,7 @@ import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.runtime.ProcessInstanceBuilder;
import org.flowable.task.api.Task;
@ -69,6 +70,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
import static cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmApprovalDetailRespVO.ActivityNode;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.bpm.enums.task.BpmReasonEnum.REJECT_CHILD_PROCESS;
import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.START_USER_NODE_ID;
import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.parseNodeType;
import static java.util.Arrays.asList;
@ -949,6 +951,29 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
status);
}
// 1.3 如果子流程拒绝设置其父流程也为拒绝状态且结束父流程
// 相关问题链接https://t.zsxq.com/kZhyb
if (Objects.equals(status, BpmProcessInstanceStatusEnum.REJECT.getStatus())
&& StrUtil.isNotBlank(instance.getSuperExecutionId())) {
// 1.3.1 获取父流程实例 并标记为不通过
Execution execution = runtimeService.createExecutionQuery().executionId(instance.getSuperExecutionId()).singleResult();
ProcessInstance parentProcessInstance = getProcessInstance(execution.getProcessInstanceId());
updateProcessInstanceReject(parentProcessInstance, BpmReasonEnum.REJECT_CHILD_PROCESS.getReason());
// 1.3.2 结束父流程需要在子流程结束事务提交后执行
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@Override
public void afterCompletion(int transactionStatus) {
// 回滚情况直接返回
if (ObjectUtil.equal(transactionStatus, TransactionSynchronization.STATUS_ROLLED_BACK)) {
return;
}
taskService.moveTaskToEnd(parentProcessInstance.getId(), BpmReasonEnum.REJECT_CHILD_PROCESS.getReason());
}
});
}
// 2. 发送对应的消息通知
if (Objects.equals(status, BpmProcessInstanceStatusEnum.APPROVE.getStatus())) {
messageService.sendMessageWhenProcessInstanceApprove(
@ -960,7 +985,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
// 3. 发送流程实例的状态事件
processInstanceEventPublisher.sendProcessInstanceResultEvent(
BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, instance, status));
BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, instance, status, reason));
// 4. 流程后置通知
if (Objects.equals(status, BpmProcessInstanceStatusEnum.APPROVE.getStatus())) {
@ -996,17 +1021,18 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
if (ObjUtil.notEqual(instance.getName(), name)) {
runtimeService.setProcessInstanceName(instance.getProcessInstanceId(), name);
}
// 流程前置通知需要在流程启动后(事务提交后)保证 variables 已设置
// 相关问题链接https://t.zsxq.com/DF7Kq
if (ObjUtil.isNull(processDefinitionInfo.getProcessBeforeTriggerSetting())) {
return;
}
BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getProcessBeforeTriggerSetting();
BpmHttpRequestUtils.executeBpmHttpRequest(instance,
setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse());
}
});
// 流程前置通知
if (ObjUtil.isNull(processDefinitionInfo.getProcessBeforeTriggerSetting())) {
return;
}
BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getProcessBeforeTriggerSetting();
BpmHttpRequestUtils.executeBpmHttpRequest(instance,
setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse());
}
}

View File

@ -804,7 +804,8 @@ public class BpmTaskServiceImpl implements BpmTaskService {
.setTargetTaskDefinitionKey(returnTaskId).setReason(reqVO.getReason()));
return;
}
// 3.2 情况二直接结束审批不通过
// 3.2 情况二 标记流程为不通过并结束流程
processInstanceService.updateProcessInstanceReject(instance, reqVO.getReason()); // 标记不通过
moveTaskToEnd(task.getProcessInstanceId(), BpmCommentTypeEnum.REJECT.formatComment(reqVO.getReason())); // 结束流程
}
@ -986,6 +987,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
}
@Override
@Transactional(rollbackFor = Exception.class)
public void moveTaskToEnd(String processInstanceId, String reason) {
List<Task> taskList = getRunningTaskListByProcessInstanceId(processInstanceId, null, null);
if (CollUtil.isEmpty(taskList)) {

View File

@ -10,7 +10,6 @@ import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.*;
@ -21,7 +20,6 @@ import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.*;
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = false) // 设置 chain = false避免用户导入有问题
public class CrmCustomerImportExcelVO {
@ExcelProperty("客户名称")

View File

@ -42,4 +42,14 @@ public interface FileApi {
String createFile(@NotEmpty(message = "文件内容不能为空") byte[] content,
String name, String directory, String type);
/**
* 生成文件预签名地址用于读取
*
* @param url 完整的文件访问地址
* @param expirationSeconds 访问有效期单位秒
* @return 文件预签名地址
*/
String presignGetUrl(@NotEmpty(message = "URL 不能为空") String url,
Integer expirationSeconds);
}

View File

@ -22,4 +22,9 @@ public class FileApiImpl implements FileApi {
return fileService.createFile(content, name, directory, type);
}
@Override
public String presignGetUrl(String url, Integer expirationSeconds) {
return fileService.presignGetUrl(url, expirationSeconds);
}
}

View File

@ -51,7 +51,7 @@ public class FileController {
}
@GetMapping("/presigned-url")
@Operation(summary = "获取文件预签名地址", description = "模式二:前端上传文件:用于前端直接上传七牛、阿里云 OSS 等文件存储器")
@Operation(summary = "获取文件预签名地址(上传)", description = "模式二:前端上传文件:用于前端直接上传七牛、阿里云 OSS 等文件存储器")
@Parameters({
@Parameter(name = "name", description = "文件名称", required = true),
@Parameter(name = "directory", description = "文件目录")
@ -59,7 +59,7 @@ public class FileController {
public CommonResult<FilePresignedUrlRespVO> getFilePresignedUrl(
@RequestParam("name") String name,
@RequestParam(value = "directory", required = false) String directory) {
return success(fileService.getFilePresignedUrl(name, directory));
return success(fileService.presignPutUrl(name, directory));
}
@PostMapping("/create")

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