Commit 2283f0cf9aebe9f5eaaadfb11d8dd6a24e756f1f

Authored by jason
2 parents 45dd87c0 466a3b06

Merge remote-tracking branch 'origin/feature/bpm' into feature/bpm

Showing 95 changed files with 1683 additions and 243 deletions
.image/工作流设计器-bpmn.jpg 0 → 100644

177 KB

.image/工作流设计器-simple.jpg 0 → 100644

127 KB

README.md
... ... @@ -149,18 +149,22 @@
149 149  
150 150 ### 工作流程
151 151  
152   -| | 功能 | 描述 |
153   -|-----|-------|----------------------------------------|
154   -| 🚀 | 流程模型 | 配置工作流的流程模型,支持文件导入与在线设计流程图,提供 7 种任务分配规则 |
155   -| 🚀 | 流程表单 | 拖动表单元素生成相应的工作流表单,覆盖 Element UI 所有的表单组件 |
156   -| 🚀 | 用户分组 | 自定义用户分组,可用于工作流的审批分组 |
157   -| 🚀 | 我的流程 | 查看我发起的工作流程,支持新建、取消流程等操作,高亮流程图、审批时间线 |
158   -| 🚀 | 待办任务 | 查看自己【未】审批的工作任务,支持通过、不通过、转发、委派、退回等操作 |
159   -| 🚀 | 已办任务 | 查看自己【已】审批的工作任务,未来会支持退回操作 |
160   -| 🚀 | OA 请假 | 作为业务自定义接入工作流的使用示例,只需创建请求对应的工作流程,即可进行审批 |
  152 +| | 功能 | 描述 |
  153 +|----|-------|-----------------------------------------|
  154 +| 🚀 | 流程模型 | 配置工作流的流程模型,支持 BPMN 和仿钉钉/飞书设计器 |
  155 +| 🚀 | 流程表单 | 拖动表单元素生成相应的工作流表单,覆盖 Element UI 所有的表单组件 |
  156 +| 🚀 | 用户分组 | 自定义用户分组,可用于工作流的审批分组 |
  157 +| 🚀 | 我的流程 | 查看我发起的工作流程,支持新建、取消流程等操作,高亮流程图、审批时间线 |
  158 +| 🚀 | 待办任务 | 查看自己【未】审批的工作任务,支持通过、不通过、转派、委派、退回、加减签等操作 |
  159 +| 🚀 | 已办任务 | 查看自己【已】审批的工作任务,支持流程预测,展示未来审批人信息 |
  160 +| 🚀 | OA 请假 | 作为业务自定义接入工作流的使用示例,只需创建请求对应的工作流程,即可进行审批 |
161 161  
162 162 ![功能图](/.image/common/bpm-feature.png)
163 163  
  164 +| BPMN 设计器 | 钉钉/飞书设计器 |
  165 +|------------------------------|--------------------------------|
  166 +| ![](/.image/工作流设计器-bpmn.jpg) | ![](/.image/工作流设计器-simple.jpg) |
  167 +
164 168 ### 支付系统
165 169  
166 170 | | 功能 | 描述 |
... ...
... ... @@ -16,7 +16,7 @@
16 16 <module>yudao-module-system</module>
17 17 <module>yudao-module-infra</module>
18 18 <!-- <module>yudao-module-member</module>-->
19   - <module>yudao-module-bpm</module>
  19 +<!-- <module>yudao-module-bpm</module>-->
20 20 <!-- <module>yudao-module-report</module>-->
21 21 <!-- <module>yudao-module-mp</module>-->
22 22 <!-- <module>yudao-module-pay</module>-->
... ... @@ -32,7 +32,7 @@
32 32 <url>https://github.com/YunaiV/ruoyi-vue-pro</url>
33 33  
34 34 <properties>
35   - <revision>2.2.0-SNAPSHOT</revision>
  35 + <revision>2.3.0-SNAPSHOT</revision>
36 36 <!-- Maven 相关 -->
37 37 <java.version>17</java.version>
38 38 <maven.compiler.source>${java.version}</maven.compiler.source>
... ...
sql/mysql/bpm_update.sql deleted
1   --- ----------------------------
2   --- 流程抄送表新加流程活动编号
3   --- ----------------------------
4   -ALTER TABLE `bpm_process_instance_copy`
5   - ADD COLUMN `activity_id` varchar(64) NULL COMMENT '流程活动编号' AFTER `category`,
6   - MODIFY COLUMN `task_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '任务编号' AFTER `category`;
7   -
8   -ALTER TABLE `bpm_process_definition_info`
9   - ADD COLUMN `model_type` tinyint NOT NULL DEFAULT 10 COMMENT '流程模型的类型' AFTER `model_id`,
10   - ADD COLUMN `simple_model` json NULL COMMENT 'SIMPLE 设计器模型数据' AFTER `form_custom_view_path`,
11   - ADD COLUMN `visible` bit(1) NOT NULL DEFAULT 1 COMMENT '是否可见' AFTER `simple_model`;
12   -
13   -ALTER TABLE `bpm_process_instance_copy`
14   - ADD COLUMN `reason` varchar(256) NULL COMMENT '抄送意见' AFTER `task_name`;
15 0 \ No newline at end of file
sql/mysql/ruoyi-vue-pro.sql
... ... @@ -11,7 +11,7 @@
11 11 Target Server Version : 80200 (8.2.0)
12 12 File Encoding : 65001
13 13  
14   - Date: 31/08/2024 09:22:45
  14 + Date: 09/11/2024 18:16:12
15 15 */
16 16  
17 17 SET NAMES utf8mb4;
... ... @@ -64,7 +64,7 @@ DROP TABLE IF EXISTS `infra_api_error_log`;
64 64 CREATE TABLE `infra_api_error_log` (
65 65 `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
66 66 `trace_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '链路追踪编号',
67   - `user_id` int NOT NULL DEFAULT 0 COMMENT '用户编号',
  67 + `user_id` bigint NOT NULL DEFAULT 0 COMMENT '用户编号',
68 68 `user_type` tinyint NOT NULL DEFAULT 0 COMMENT '用户类型',
69 69 `application_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '应用名',
70 70 `request_method` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '请求方法名',
... ... @@ -91,7 +91,7 @@ CREATE TABLE `infra_api_error_log` (
91 91 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
92 92 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
93 93 PRIMARY KEY (`id`) USING BTREE
94   -) ENGINE = InnoDB AUTO_INCREMENT = 20014 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志';
  94 +) ENGINE = InnoDB AUTO_INCREMENT = 21213 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志';
95 95  
96 96 -- ----------------------------
97 97 -- Records of infra_api_error_log
... ... @@ -250,7 +250,7 @@ CREATE TABLE `infra_file` (
250 250 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
251 251 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
252 252 PRIMARY KEY (`id`) USING BTREE
253   -) ENGINE = InnoDB AUTO_INCREMENT = 1472 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表';
  253 +) ENGINE = InnoDB AUTO_INCREMENT = 1558 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表';
254 254  
255 255 -- ----------------------------
256 256 -- Records of infra_file
... ... @@ -275,14 +275,19 @@ CREATE TABLE `infra_file_config` (
275 275 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
276 276 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
277 277 PRIMARY KEY (`id`) USING BTREE
278   -) ENGINE = InnoDB AUTO_INCREMENT = 24 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件配置表';
  278 +) ENGINE = InnoDB AUTO_INCREMENT = 29 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件配置表';
279 279  
280 280 -- ----------------------------
281 281 -- Records of infra_file_config
282 282 -- ----------------------------
283 283 BEGIN;
284   -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', '2024-02-28 22:54:07', b'0');
285   -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\"}', '1', '2024-01-13 22:11:12', '1', '2024-04-03 19:38:34', b'0');
  284 +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', '2024-11-09 18:09:28', b'0');
  285 +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\"}', '1', '2024-01-13 22:11:12', '1', '2024-11-09 18:09:28', b'0');
  286 +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', '2024-11-09 18:15:39', b'0');
  287 +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\"}', '1', '2024-11-09 16:47:08', '1', '2024-11-09 18:15:43', b'0');
  288 +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==\"}', '1', '2024-11-09 16:56:42', '1', '2024-11-09 18:15:46', b'0');
  289 +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\"}', '1', '2024-11-09 17:18:41', '1', '2024-11-09 18:15:49', b'0');
  290 +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\"}', '1', '2024-11-09 17:43:10', '1', '2024-11-09 18:15:52', b'0');
286 291 COMMIT;
287 292  
288 293 -- ----------------------------
... ... @@ -328,13 +333,13 @@ CREATE TABLE `infra_job` (
328 333 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
329 334 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
330 335 PRIMARY KEY (`id`) USING BTREE
331   -) ENGINE = InnoDB AUTO_INCREMENT = 32 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务表';
  336 +) ENGINE = InnoDB AUTO_INCREMENT = 34 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务表';
332 337  
333 338 -- ----------------------------
334 339 -- Records of infra_job
335 340 -- ----------------------------
336 341 BEGIN;
337   -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 (5, '支付通知 Job', 2, 'payNotifyJob', NULL, '* * * * * ?', 0, 0, 0, '1', '2021-10-27 08:34:42', '1', '2023-07-09 20:51:41', b'0');
  342 +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 (5, '支付通知 Job', 2, 'payNotifyJob', NULL, '* * * * * ?', 0, 0, 0, '1', '2021-10-27 08:34:42', '1', '2024-09-12 13:32:48', b'0');
338 343 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 (17, '支付订单同步 Job', 2, 'payOrderSyncJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-22 14:36:26', '1', '2023-07-22 15:39:08', b'0');
339 344 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 (18, '支付订单过期 Job', 2, 'payOrderExpireJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-22 15:36:23', '1', '2023-07-22 15:39:54', b'0');
340 345 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 (19, '退款订单的同步 Job', 2, 'payRefundSyncJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-23 21:03:44', '1', '2023-07-23 21:09:00', b'0');
... ... @@ -344,7 +349,8 @@ INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`
344 349 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 (24, '佣金解冻 Job', 2, 'brokerageRecordUnfreezeJob', '', '0 * * * * ?', 3, 0, 0, '1', '2023-09-28 22:01:46', '1', '2023-09-28 22:01:56', b'0');
345 350 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 (25, '访问日志清理 Job', 2, 'accessLogCleanJob', '', '0 0 0 * * ?', 3, 0, 0, '1', '2023-10-03 10:59:41', '1', '2023-10-03 11:01:10', b'0');
346 351 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 (26, '错误日志清理 Job', 2, 'errorLogCleanJob', '', '0 0 0 * * ?', 3, 0, 0, '1', '2023-10-03 11:00:43', '1', '2023-10-03 11:01:12', b'0');
347   -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', '2023-10-03 11:01:42', b'0');
  352 +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');
  353 +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', '2024-10-27 19:40:23', b'0');
348 354 COMMIT;
349 355  
350 356 -- ----------------------------
... ... @@ -368,7 +374,7 @@ CREATE TABLE `infra_job_log` (
368 374 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
369 375 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
370 376 PRIMARY KEY (`id`) USING BTREE
371   -) ENGINE = InnoDB AUTO_INCREMENT = 395 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务日志表';
  377 +) ENGINE = InnoDB AUTO_INCREMENT = 638 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务日志表';
372 378  
373 379 -- ----------------------------
374 380 -- Records of infra_job_log
... ... @@ -405,7 +411,7 @@ BEGIN;
405 411 INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (100, '芋道源码', 0, 0, 1, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2023-11-14 23:30:36', b'0', 1);
406 412 INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (101, '深圳总公司', 100, 1, 104, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2023-12-02 09:53:35', b'0', 1);
407 413 INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (102, '长沙分公司', 100, 2, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-12-15 05:01:40', b'0', 1);
408   -INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (103, '研发部门', 101, 1, 104, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2024-03-24 20:56:04', b'0', 1);
  414 +INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (103, '研发部门', 101, 1, 1, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2024-10-02 10:22:03', b'0', 1);
409 415 INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (104, '市场部门', 101, 2, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-12-15 05:01:38', b'0', 1);
410 416 INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (105, '测试部门', 101, 3, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2022-05-16 20:25:15', b'0', 1);
411 417 INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (106, '财务部门', 101, 4, 103, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '103', '2022-01-15 21:32:22', b'0', 1);
... ... @@ -438,7 +444,7 @@ CREATE TABLE `system_dict_data` (
438 444 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
439 445 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
440 446 PRIMARY KEY (`id`) USING BTREE
441   -) ENGINE = InnoDB AUTO_INCREMENT = 1592 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典数据表';
  447 +) ENGINE = InnoDB AUTO_INCREMENT = 1683 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典数据表';
442 448  
443 449 -- ----------------------------
444 450 -- Records of system_dict_data
... ... @@ -509,6 +515,7 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st
509 515 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 (86, 0, '病假', '1', 'bpm_oa_leave_type', 0, 'primary', '', NULL, '1', '2021-09-21 22:35:28', '1', '2022-02-16 10:00:41', b'0');
510 516 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 (87, 1, '事假', '2', 'bpm_oa_leave_type', 0, 'info', '', NULL, '1', '2021-09-21 22:36:11', '1', '2022-02-16 10:00:49', b'0');
511 517 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 (88, 2, '婚假', '3', 'bpm_oa_leave_type', 0, 'warning', '', NULL, '1', '2021-09-21 22:36:38', '1', '2022-02-16 10:00:53', b'0');
  518 +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 (112, 0, '微信 Wap 网站支付', 'wx_wap', 'pay_channel_code', 0, 'success', '', '微信 Wap 网站支付', '1', '2023-07-19 20:08:06', '1', '2023-07-19 20:09:08', b'0');
512 519 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 (113, 1, '微信公众号支付', 'wx_pub', 'pay_channel_code', 0, 'success', '', '微信公众号支付', '1', '2021-12-03 10:40:24', '1', '2023-07-19 20:08:47', b'0');
513 520 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 (114, 2, '微信小程序支付', 'wx_lite', 'pay_channel_code', 0, 'success', '', '微信小程序支付', '1', '2021-12-03 10:41:06', '1', '2023-07-19 20:08:50', b'0');
514 521 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 (115, 3, '微信 App 支付', 'wx_app', 'pay_channel_code', 0, 'success', '', '微信 App 支付', '1', '2021-12-03 10:41:20', '1', '2023-07-19 20:08:56', b'0');
... ... @@ -597,8 +604,8 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st
597 604 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 (1198, 32, '安卓 App', '32', 'terminal', 0, 'default', '', '终端 - 安卓 App', '1', '2022-12-10 10:55:02', '1', '2022-12-10 10:59:17', b'0');
598 605 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 (1199, 0, '普通订单', '0', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 普通订单', '1', '2022-12-10 16:34:14', '1', '2022-12-10 16:34:14', b'0');
599 606 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 (1200, 1, '秒杀订单', '1', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 秒杀订单', '1', '2022-12-10 16:34:26', '1', '2022-12-10 16:34:26', b'0');
600   -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 (1201, 2, '拼团订单', '2', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 拼团订单', '1', '2022-12-10 16:34:36', '1', '2022-12-10 16:34:36', b'0');
601   -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 (1202, 3, '砍价订单', '3', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 砍价订单', '1', '2022-12-10 16:34:48', '1', '2022-12-10 16:34:48', b'0');
  607 +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 (1201, 2, '砍价订单', '2', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 拼团订单', '1', '2022-12-10 16:34:36', '1', '2024-09-07 14:18:39', b'0');
  608 +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 (1202, 3, '拼团订单', '3', 'trade_order_type', 0, 'default', '', '交易订单的类型 - 砍价订单', '1', '2022-12-10 16:34:48', '1', '2024-09-07 14:18:32', b'0');
602 609 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 (1203, 0, '待支付', '0', 'trade_order_status', 0, 'default', '', '交易订单状态 - 待支付', '1', '2022-12-10 16:49:29', '1', '2022-12-10 16:49:29', b'0');
603 610 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 (1204, 10, '待发货', '10', 'trade_order_status', 0, 'primary', '', '交易订单状态 - 待发货', '1', '2022-12-10 16:49:53', '1', '2022-12-10 16:51:17', b'0');
604 611 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 (1205, 20, '已发货', '20', 'trade_order_status', 0, 'primary', '', '交易订单状态 - 已发货', '1', '2022-12-10 16:50:13', '1', '2022-12-10 16:51:31', b'0');
... ... @@ -628,7 +635,6 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st
628 635 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');
629 636 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');
630 637 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');
631   -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 (1233, 21, 'Vue3 Element Plus Schema 模版', '21', 'infra_codegen_front_type', 0, '', '', '', '1', '2023-04-13 00:04:26', '1', '2023-04-13 00:04:26', b'0');
632 638 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, 'Vue3 vben 模版', '30', 'infra_codegen_front_type', 0, '', '', '', '1', '2023-04-13 00:04:26', '1', '2023-04-13 00:04:26', b'0');
633 639 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');
634 640 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');
... ... @@ -660,7 +666,7 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st
660 666 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 (1363, 3, '覆盖绑定', '3', 'brokerage_bind_mode', 0, '', '', '如果用户已经有推广人,推广人会被变更', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0');
661 667 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 (1364, 1, '钱包', '1', 'brokerage_withdraw_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0');
662 668 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 (1365, 2, '银行卡', '2', 'brokerage_withdraw_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0');
663   -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 (1366, 3, '微信', '3', 'brokerage_withdraw_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0');
  669 +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 (1366, 3, '微信', '3', 'brokerage_withdraw_type', 0, '', '', '手动打款', '', '2023-09-28 02:46:05', '1', '2024-10-13 11:06:54', b'0');
664 670 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 (1367, 4, '支付宝', '4', 'brokerage_withdraw_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0');
665 671 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 (1368, 1, '订单返佣', '1', 'brokerage_record_biz_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0');
666 672 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 (1369, 2, '申请提现', '2', 'brokerage_record_biz_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', b'0');
... ... @@ -683,9 +689,9 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st
683 689 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 (1386, 1, '砍价中', '1', 'promotion_bargain_record_status', 0, 'default', '', '', '1', '2023-10-05 10:41:26', '1', '2023-10-05 10:41:26', b'0');
684 690 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 (1387, 2, '砍价成功', '2', 'promotion_bargain_record_status', 0, 'success', '', '', '1', '2023-10-05 10:41:39', '1', '2023-10-05 10:41:39', b'0');
685 691 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 (1388, 3, '砍价失败', '3', 'promotion_bargain_record_status', 0, 'warning', '', '', '1', '2023-10-05 10:41:57', '1', '2023-10-05 10:41:57', b'0');
686   -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 (1389, 1, '拼团中', '1', 'promotion_combination_record_status', 0, '', '', '', '1', '2023-10-08 07:24:44', '1', '2023-10-08 07:24:44', b'0');
687   -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 (1390, 2, '拼团成功', '2', 'promotion_combination_record_status', 0, 'success', '', '', '1', '2023-10-08 07:24:56', '1', '2023-10-08 07:24:56', b'0');
688   -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 (1391, 3, '拼团失败', '3', 'promotion_combination_record_status', 0, 'warning', '', '', '1', '2023-10-08 07:25:11', '1', '2023-10-08 07:25:11', b'0');
  692 +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 (1389, 0, '拼团中', '0', 'promotion_combination_record_status', 0, '', '', '', '1', '2023-10-08 07:24:44', '1', '2024-10-13 10:08:17', b'0');
  693 +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 (1390, 1, '拼团成功', '1', 'promotion_combination_record_status', 0, 'success', '', '', '1', '2023-10-08 07:24:56', '1', '2024-10-13 10:08:20', b'0');
  694 +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 (1391, 2, '拼团失败', '2', 'promotion_combination_record_status', 0, 'warning', '', '', '1', '2023-10-08 07:25:11', '1', '2024-10-13 10:08:24', b'0');
689 695 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 (1392, 2, '管理员修改', '2', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:41:34', '1', '2023-10-11 07:41:34', b'0');
690 696 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 (1393, 13, '订单积分抵扣(单个退款)', '13', 'member_point_biz_type', 0, '', '', '', '1', '2023-10-11 07:42:29', '1', '2023-10-11 07:42:29', b'0');
691 697 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 (1394, 21, '订单积分奖励', '21', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:42:44', '1', '2023-10-11 07:42:44', b'0');
... ... @@ -862,6 +868,33 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st
862 868 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 (1589, 10, 'BPMN 设计器', '10', 'bpm_model_type', 0, 'primary', '', '', '1', '2024-08-26 15:22:17', '1', '2024-08-26 16:46:02', b'0');
863 869 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 (1590, 20, 'SIMPLE 设计器', '20', 'bpm_model_type', 0, 'success', '', '', '1', '2024-08-26 15:22:27', '1', '2024-08-26 16:45:58', b'0');
864 870 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 (1591, 4, '七牛云', 'QINIU', 'system_sms_channel_code', 0, '', '', '', '1', '2024-08-31 08:45:03', '1', '2024-08-31 08:45:24', b'0');
  871 +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 (1592, 3, '新人券', '3', 'promotion_coupon_take_type', 0, 'info', '', '新人注册后,自动发放', '1', '2024-09-03 11:57:16', '1', '2024-09-03 11:57:28', b'0');
  872 +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 (1593, 5, '微信零钱', '5', 'brokerage_withdraw_type', 0, '', '', '自动打款', '1', '2024-10-13 11:06:48', '1', '2024-10-13 11:06:59', b'0');
  873 +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 (1655, 0, '标准数据格式(JSON)', '0', 'iot_data_format', 0, 'default', '', '', '1', '2024-08-10 11:53:26', '1', '2024-09-06 14:31:02', b'0');
  874 +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 (1656, 1, '透传/自定义', '1', 'iot_data_format', 0, 'default', '', '', '1', '2024-08-10 11:53:37', '1', '2024-09-06 14:30:54', b'0');
  875 +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 (1657, 0, '直连设备', '0', 'iot_product_device_type', 0, 'default', '', '', '1', '2024-08-10 11:54:58', '1', '2024-09-06 21:57:01', b'0');
  876 +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 (1658, 2, '网关设备', '2', 'iot_product_device_type', 0, 'default', '', '', '1', '2024-08-10 11:55:08', '1', '2024-09-06 21:56:46', b'0');
  877 +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 (1659, 1, '网关子设备', '1', 'iot_product_device_type', 0, 'default', '', '', '1', '2024-08-10 11:55:20', '1', '2024-09-06 21:57:10', b'0');
  878 +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 (1661, 1, '已发布', '1', 'iot_product_status', 0, 'success', '', '', '1', '2024-08-10 12:10:33', '1', '2024-09-06 22:06:22', b'0');
  879 +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 (1663, 0, '开发中', '0', 'iot_product_status', 0, 'default', '', '', '1', '2024-08-10 14:19:18', '1', '2024-09-07 10:58:07', b'0');
  880 +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 (1665, 0, '弱校验', '0', 'iot_validate_type', 0, '', '', '', '1', '2024-09-06 20:05:48', '1', '2024-09-06 22:02:44', b'0');
  881 +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 (1666, 1, '免校验', '1', 'iot_validate_type', 0, '', '', '', '1', '2024-09-06 20:06:03', '1', '2024-09-06 22:02:51', b'0');
  882 +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 (1667, 0, 'Wi-Fi', '0', 'iot_net_type', 0, '', '', '', '1', '2024-09-06 22:04:47', '1', '2024-09-06 22:04:47', b'0');
  883 +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 (1668, 1, '蜂窝(2G / 3G / 4G / 5G)', '1', 'iot_net_type', 0, '', '', '', '1', '2024-09-06 22:05:14', '1', '2024-09-06 22:05:14', b'0');
  884 +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 (1669, 2, '以太网', '2', 'iot_net_type', 0, '', '', '', '1', '2024-09-06 22:05:35', '1', '2024-09-06 22:05:35', b'0');
  885 +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 (1670, 3, '其他', '3', 'iot_net_type', 0, '', '', '', '1', '2024-09-06 22:05:52', '1', '2024-09-06 22:05:52', b'0');
  886 +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 (1671, 0, '自定义', '0', 'iot_protocol_type', 0, '', '', '', '1', '2024-09-06 22:26:10', '1', '2024-09-06 22:26:10', b'0');
  887 +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 (1672, 1, 'Modbus', '1', 'iot_protocol_type', 0, '', '', '', '1', '2024-09-06 22:26:21', '1', '2024-09-06 22:26:21', b'0');
  888 +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 (1673, 2, 'OPC UA', '2', 'iot_protocol_type', 0, '', '', '', '1', '2024-09-06 22:26:31', '1', '2024-09-06 22:26:31', b'0');
  889 +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 (1674, 3, 'ZigBee', '3', 'iot_protocol_type', 0, '', '', '', '1', '2024-09-06 22:26:39', '1', '2024-09-06 22:26:39', b'0');
  890 +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 (1675, 4, 'BLE', '4', 'iot_protocol_type', 0, '', '', '', '1', '2024-09-06 22:26:48', '1', '2024-09-06 22:26:48', b'0');
  891 +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 (1676, 0, '未激活', '0', 'iot_device_status', 0, '', '', '', '1', '2024-09-21 08:13:34', '1', '2024-09-21 08:13:34', b'0');
  892 +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 (1677, 1, '在线', '1', 'iot_device_status', 0, '', '', '', '1', '2024-09-21 08:13:48', '1', '2024-09-21 08:13:48', b'0');
  893 +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 (1678, 2, '离线', '2', 'iot_device_status', 0, '', '', '', '1', '2024-09-21 08:13:59', '1', '2024-09-21 08:13:59', b'0');
  894 +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 (1679, 3, '已禁用', '3', 'iot_device_status', 0, '', '', '', '1', '2024-09-21 08:14:13', '1', '2024-09-21 08:14:13', b'0');
  895 +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 (1680, 1, '属性', '1', 'iot_product_function_type', 0, '', '', '', '1', '2024-09-29 20:03:01', '1', '2024-09-29 20:09:41', b'0');
  896 +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 (1681, 2, '服务', '2', 'iot_product_function_type', 0, '', '', '', '1', '2024-09-29 20:03:11', '1', '2024-09-29 20:08:23', b'0');
  897 +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 (1682, 3, '事件', '3', 'iot_product_function_type', 0, '', '', '', '1', '2024-09-29 20:03:20', '1', '2024-09-29 20:08:20', b'0');
865 898 COMMIT;
866 899  
867 900 -- ----------------------------
... ... @@ -881,7 +914,7 @@ CREATE TABLE `system_dict_type` (
881 914 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
882 915 `deleted_time` datetime NULL DEFAULT NULL COMMENT '删除时间',
883 916 PRIMARY KEY (`id`) USING BTREE
884   -) ENGINE = InnoDB AUTO_INCREMENT = 630 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表';
  917 +) ENGINE = InnoDB AUTO_INCREMENT = 640 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表';
885 918  
886 919 -- ----------------------------
887 920 -- Records of system_dict_type
... ... @@ -980,6 +1013,14 @@ INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creat
980 1013 INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (627, '写作格式', 'ai_write_format', 0, '', '1', '2024-07-07 15:14:34', '1', '2024-07-07 15:14:34', b'0', '1970-01-01 00:00:00');
981 1014 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');
982 1015 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');
  1016 +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (630, 'IOT 接入网关协议', 'iot_protocol_type', 0, '', '1', '2024-09-06 22:20:17', '1', '2024-09-06 22:20:17', b'0', '1970-01-01 00:00:00');
  1017 +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (631, 'IOT 设备状态', 'iot_device_status', 0, '', '1', '2024-09-21 08:12:55', '1', '2024-09-21 08:12:55', b'0', '1970-01-01 00:00:00');
  1018 +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (632, 'IOT 物模型功能类型', 'iot_product_function_type', 0, '', '1', '2024-09-29 20:02:36', '1', '2024-09-29 20:09:26', b'0', '1970-01-01 00:00:00');
  1019 +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (634, 'IOT 数据格式', 'iot_data_format', 0, '', '1', '2024-08-10 11:52:58', '1', '2024-09-06 14:30:14', b'0', '1970-01-01 00:00:00');
  1020 +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (635, 'IOT 产品设备类型', 'iot_product_device_type', 0, '', '1', '2024-08-10 11:54:30', '1', '2024-08-10 04:06:56', b'0', '1970-01-01 00:00:00');
  1021 +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (637, 'IOT 产品状态', 'iot_product_status', 0, '', '1', '2024-08-10 12:06:09', '1', '2024-08-10 12:06:09', b'0', '1970-01-01 00:00:00');
  1022 +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (638, 'IOT 数据校验级别', 'iot_validate_type', 0, '', '1', '2024-09-06 20:05:13', '1', '2024-09-06 20:05:13', b'0', '1970-01-01 00:00:00');
  1023 +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (639, 'IOT 联网方式', 'iot_net_type', 0, '', '1', '2024-09-06 22:04:13', '1', '2024-09-06 22:04:13', b'0', '1970-01-01 00:00:00');
983 1024 COMMIT;
984 1025  
985 1026 -- ----------------------------
... ... @@ -1003,7 +1044,7 @@ CREATE TABLE `system_login_log` (
1003 1044 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
1004 1045 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
1005 1046 PRIMARY KEY (`id`) USING BTREE
1006   -) ENGINE = InnoDB AUTO_INCREMENT = 3289 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录';
  1047 +) ENGINE = InnoDB AUTO_INCREMENT = 3370 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录';
1007 1048  
1008 1049 -- ----------------------------
1009 1050 -- Records of system_login_log
... ... @@ -1069,7 +1110,7 @@ CREATE TABLE `system_mail_log` (
1069 1110 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
1070 1111 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
1071 1112 PRIMARY KEY (`id`) USING BTREE
1072   -) ENGINE = InnoDB AUTO_INCREMENT = 356 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '邮件日志表';
  1113 +) ENGINE = InnoDB AUTO_INCREMENT = 359 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '邮件日志表';
1073 1114  
1074 1115 -- ----------------------------
1075 1116 -- Records of system_mail_log
... ... @@ -1134,7 +1175,7 @@ CREATE TABLE `system_menu` (
1134 1175 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
1135 1176 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
1136 1177 PRIMARY KEY (`id`) USING BTREE
1137   -) ENGINE = InnoDB AUTO_INCREMENT = 2808 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '菜单权限表';
  1178 +) ENGINE = InnoDB AUTO_INCREMENT = 2912 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '菜单权限表';
1138 1179  
1139 1180 -- ----------------------------
1140 1181 -- Records of system_menu
... ... @@ -1332,7 +1373,7 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i
1332 1373 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 (1241, '文件配置删除', 'infra:file-config:delete', 3, 4, 1237, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', b'0');
1333 1374 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 (1242, '文件配置导出', 'infra:file-config:export', 3, 5, 1237, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', b'0');
1334 1375 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 (1243, '文件管理', '', 2, 6, 2, 'file', 'ep:files', NULL, '', 0, b'1', b'1', b'1', '1', '2022-03-16 23:47:40', '1', '2024-04-23 00:02:11', b'0');
1335   -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 (1254, '作者动态', '', 1, 0, 0, 'https://www.iocoder.cn', 'ep:avatar', NULL, NULL, 0, b'1', b'1', b'1', '1', '2022-04-23 01:03:15', '1', '2023-12-08 23:40:01', b'0');
  1376 +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 (1254, '作者动态', '', 1, 0, 0, 'https://www.iocoder.cn', 'ep:avatar', NULL, NULL, 0, b'1', b'1', b'1', '1', '2022-04-23 01:03:15', '1', '2024-09-06 09:19:42', b'0');
1336 1377 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 (1255, '数据源配置', '', 2, 1, 2, 'data-source-config', 'ep:data-analysis', 'infra/dataSourceConfig/index', 'InfraDataSourceConfig', 0, b'1', b'1', b'1', '', '2022-04-27 14:37:32', '1', '2024-02-29 08:51:25', b'0');
1337 1378 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 (1256, '数据源配置查询', 'infra:data-source-config:query', 3, 1, 1255, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', b'0');
1338 1379 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 (1257, '数据源配置创建', 'infra:data-source-config:create', 3, 2, 1255, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', b'0');
... ... @@ -1589,7 +1630,7 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i
1589 1630 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 (2361, '交易统计导出', 'statistics:trade:export', 3, 2, 2359, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-09-30 03:22:40', '', '2023-09-30 03:22:40', b'0');
1590 1631 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 (2362, '商城系统', '', 1, 59, 0, '/mall', 'ep:shop', '', '', 0, b'1', b'1', b'1', '1', '2023-09-30 11:52:02', '1', '2023-09-30 11:52:18', b'0');
1591 1632 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 (2363, '用户积分修改', 'member:user:update-point', 3, 6, 2317, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-01 14:39:43', '', '2023-10-01 14:39:43', b'0');
1592   -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 (2364, '用户余额修改', 'member:user:update-balance', 3, 7, 2317, '', '', '', '', 0, b'1', b'1', b'1', '', '2023-10-01 14:39:43', '1', '2023-10-01 22:42:31', b'0');
  1633 +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 (2364, '用户余额修改', 'pay:wallet:update-balance', 3, 7, 2317, '', '', '', '', 0, b'1', b'1', b'1', '', '2023-10-01 14:39:43', '1', '2024-10-01 09:42:57', b'0');
1593 1634 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 (2365, '优惠劵', '', 1, 2, 2030, 'coupon', 'fa-solid:disease', '', '', 0, b'1', b'1', b'1', '1', '2023-10-03 12:39:15', '1', '2023-10-05 00:16:07', b'0');
1594 1635 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 (2366, '砍价记录', '', 2, 2, 2310, 'record', 'ep:list', 'mall/promotion/bargain/record/index', 'PromotionBargainRecord', 0, b'1', b'1', b'1', '', '2023-10-05 02:49:06', '1', '2023-10-05 10:50:38', b'0');
1595 1636 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 (2367, '砍价记录查询', 'promotion:bargain-record:query', 3, 1, 2366, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-05 02:49:06', '', '2023-10-05 02:49:06', b'0');
... ... @@ -1977,6 +2018,32 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i
1977 2018 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 (2805, '会话删除', 'promotion:kefu-conversation:delete', 3, 3, 2797, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-08-31 09:19:51', '1', '2024-08-31 09:20:32', b'0');
1978 2019 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 (2806, '消息发送', 'promotion:kefu-message:send', 3, 12, 2797, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-08-31 09:20:06', '1', '2024-08-31 09:20:06', b'0');
1979 2020 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 (2807, '消息更新', 'promotion:kefu-message:update', 3, 11, 2797, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-08-31 09:20:22', '1', '2024-08-31 09:20:22', b'0');
  2021 +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 (2808, '积分商城', '', 2, 5, 2030, 'point-activity', 'ep:bowl', 'mall/promotion/point/activity/index', 'PointActivity', 0, b'1', b'1', b'1', '', '2024-09-21 05:36:42', '1', '2024-09-23 09:14:43', b'0');
  2022 +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 (2809, '积分商城活动查询', 'promotion:point-activity:query', 3, 1, 2808, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-09-21 05:36:42', '1', '2024-09-22 14:49:05', b'0');
  2023 +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 (2810, '积分商城活动创建', 'promotion:point-activity:create', 3, 2, 2808, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-09-21 05:36:42', '1', '2024-09-22 14:49:08', b'0');
  2024 +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 (2811, '积分商城活动更新', 'promotion:point-activity:update', 3, 3, 2808, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-09-21 05:36:42', '1', '2024-09-22 14:49:10', b'0');
  2025 +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 (2812, '积分商城活动删除', 'promotion:point-activity:delete', 3, 4, 2808, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-09-21 05:36:42', '1', '2024-09-22 14:49:12', b'0');
  2026 +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 (2813, '积分商城活动导出', 'promotion:point-activity:export', 3, 5, 2808, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-09-21 05:36:42', '1', '2024-09-22 14:49:27', b'0');
  2027 +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 (2892, 'IOT 物联网', '', 1, 500, 0, '/iot', 'fa-solid:hdd', '', '', 0, b'1', b'1', b'1', '1', '2024-08-10 09:55:29', '1', '2024-08-10 09:55:29', b'0');
  2028 +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 (2893, '设备接入', '', 1, 1, 2892, 'device', 'ep:platform', '', '', 0, b'1', b'1', b'1', '1', '2024-08-10 09:57:56', '1', '2024-10-20 18:57:43', b'0');
  2029 +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 (2894, '产品管理', '', 2, 0, 2893, 'product', '', 'iot/product/index', 'IoTProduct', 0, b'1', b'1', b'1', '', '2024-08-10 02:38:02', '1', '2024-09-16 19:50:42', b'0');
  2030 +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 (2895, '产品查询', 'iot:product:query', 3, 1, 2894, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-08-10 02:38:02', '', '2024-08-10 02:38:02', b'0');
  2031 +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 (2896, '产品创建', 'iot:product:create', 3, 2, 2894, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-08-10 02:38:02', '', '2024-08-10 02:38:02', b'0');
  2032 +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 (2897, '产品更新', 'iot:product:update', 3, 3, 2894, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-08-10 02:38:02', '', '2024-08-10 02:38:02', b'0');
  2033 +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 (2898, '产品删除', 'iot:product:delete', 3, 4, 2894, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-08-10 02:38:02', '', '2024-08-10 02:38:02', b'0');
  2034 +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 (2899, '产品导出', 'iot:product:export', 3, 5, 2894, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-08-10 02:38:02', '', '2024-08-10 02:38:02', b'0');
  2035 +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 (2900, '设备管理', '', 2, 0, 2893, 'device', '', 'iot/device/index', 'IoTDevice', 0, b'1', b'1', b'1', '', '2024-09-16 18:48:19', '1', '2024-09-16 19:50:53', b'0');
  2036 +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 (2901, '设备查询', 'iot:device:query', 3, 1, 2900, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-09-16 18:48:19', '1', '2024-09-16 19:37:00', b'0');
  2037 +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 (2902, '设备创建', 'iot:device:create', 3, 2, 2900, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-09-16 18:48:19', '1', '2024-09-16 19:37:09', b'0');
  2038 +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 (2903, '设备更新', 'iot:device:update', 3, 3, 2900, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-09-16 18:48:19', '1', '2024-09-16 19:37:18', b'0');
  2039 +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 (2904, '设备删除', 'iot:device:delete', 3, 4, 2900, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-09-16 18:48:19', '1', '2024-09-16 19:37:42', b'0');
  2040 +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 (2905, '设备导出', 'iot:device:export', 3, 5, 2900, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-09-16 18:48:19', '1', '2024-09-16 19:37:49', b'0');
  2041 +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 (2906, 'IoT 产品物模型管理', '', 1, 0, 2893, 'think-model-function', '', '', '', 0, b'0', b'1', b'1', '', '2024-09-25 22:12:09', '1', '2024-09-29 20:52:12', b'0');
  2042 +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 (2907, 'IoT 产品物模型查询', 'iot:think-model-function:query', 3, 1, 2906, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-09-25 22:12:09', '', '2024-09-25 22:12:09', b'0');
  2043 +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 (2908, 'IoT 产品物模型创建', 'iot:think-model-function:create', 3, 2, 2906, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-09-25 22:12:09', '', '2024-09-25 22:12:09', b'0');
  2044 +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 (2909, 'IoT 产品物模型更新', 'iot:think-model-function:update', 3, 3, 2906, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-09-25 22:12:09', '', '2024-09-25 22:12:09', b'0');
  2045 +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 (2910, 'IoT 产品物模型删除', 'iot:think-model-function:delete', 3, 4, 2906, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-09-25 22:12:09', '', '2024-09-25 22:12:09', b'0');
  2046 +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 (2911, 'IoT 产品物模型导出', 'iot:think-model-function:export', 3, 5, 2906, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-09-25 22:12:09', '', '2024-09-25 22:12:09', b'0');
1980 2047 COMMIT;
1981 2048  
1982 2049 -- ----------------------------
... ... @@ -2003,7 +2070,7 @@ CREATE TABLE `system_notice` (
2003 2070 -- ----------------------------
2004 2071 BEGIN;
2005 2072 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);
2006   -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=\"\" style=\"\"/>11112222</p>', 2, 1, 'admin', '2021-01-05 17:03:48', '1', '2023-12-02 20:07:26', b'0', 1);
  2073 +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=\"\" style=\"\"/>11112222<img src=\"http://test.yudao.iocoder.cn/fe44fc7bdb82ca421184b2eebbaee9e2148d4a1827479a4eb4521e11d2a062ba.png\" alt=\"image\" data-href=\"http://test.yudao.iocoder.cn/fe44fc7bdb82ca421184b2eebbaee9e2148d4a1827479a4eb4521e11d2a062ba.png\" style=\"\"/></p>', 2, 1, 'admin', '2021-01-05 17:03:48', '1', '2024-09-24 20:48:09', b'0', 1);
2007 2074 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);
2008 2075 COMMIT;
2009 2076  
... ... @@ -2098,7 +2165,7 @@ CREATE TABLE `system_oauth2_access_token` (
2098 2165 PRIMARY KEY (`id`) USING BTREE,
2099 2166 INDEX `idx_access_token`(`access_token` ASC) USING BTREE,
2100 2167 INDEX `idx_refresh_token`(`refresh_token` ASC) USING BTREE
2101   -) ENGINE = InnoDB AUTO_INCREMENT = 9563 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌';
  2168 +) ENGINE = InnoDB AUTO_INCREMENT = 11308 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌';
2102 2169  
2103 2170 -- ----------------------------
2104 2171 -- Records of system_oauth2_access_token
... ... @@ -2220,7 +2287,7 @@ CREATE TABLE `system_oauth2_refresh_token` (
2220 2287 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
2221 2288 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
2222 2289 PRIMARY KEY (`id`) USING BTREE
2223   -) ENGINE = InnoDB AUTO_INCREMENT = 1620 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 刷新令牌';
  2290 +) ENGINE = InnoDB AUTO_INCREMENT = 1676 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 刷新令牌';
2224 2291  
2225 2292 -- ----------------------------
2226 2293 -- Records of system_oauth2_refresh_token
... ... @@ -2253,7 +2320,7 @@ CREATE TABLE `system_operate_log` (
2253 2320 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
2254 2321 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
2255 2322 PRIMARY KEY (`id`) USING BTREE
2256   -) ENGINE = InnoDB AUTO_INCREMENT = 9056 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '操作日志记录 V2 版本';
  2323 +) ENGINE = InnoDB AUTO_INCREMENT = 9064 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '操作日志记录 V2 版本';
2257 2324  
2258 2325 -- ----------------------------
2259 2326 -- Records of system_operate_log
... ... @@ -3203,7 +3270,7 @@ CREATE TABLE `system_sms_channel` (
3203 3270 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
3204 3271 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
3205 3272 PRIMARY KEY (`id`) USING BTREE
3206   -) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信渠道';
  3273 +) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信渠道';
3207 3274  
3208 3275 -- ----------------------------
3209 3276 -- Records of system_sms_channel
... ... @@ -3211,6 +3278,7 @@ CREATE TABLE `system_sms_channel` (
3211 3278 BEGIN;
3212 3279 INSERT INTO `system_sms_channel` (`id`, `signature`, `code`, `status`, `remark`, `api_key`, `api_secret`, `callback_url`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2, 'Ballcat', 'ALIYUN', 0, '你要改哦,只有我可以用!!!!', 'LTAI5tCnKso2uG3kJ5gRav88', 'fGJ5SNXL7P1NHNRmJ7DJaMJGPyE55C', NULL, '', '2021-03-31 11:53:10', '1', '2024-08-04 08:53:26', b'0');
3213 3280 INSERT INTO `system_sms_channel` (`id`, `signature`, `code`, `status`, `remark`, `api_key`, `api_secret`, `callback_url`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4, '测试渠道', 'DEBUG_DING_TALK', 0, '123', '696b5d8ead48071237e4aa5861ff08dbadb2b4ded1c688a7b7c9afc615579859', 'SEC5c4e5ff888bc8a9923ae47f59e7ccd30af1f14d93c55b4e2c9cb094e35aeed67', NULL, '1', '2021-04-13 00:23:14', '1', '2022-03-27 20:29:49', b'0');
  3281 +INSERT INTO `system_sms_channel` (`id`, `signature`, `code`, `status`, `remark`, `api_key`, `api_secret`, `callback_url`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (7, 'mock腾讯云', 'TENCENT', 0, '', '1 2', '2 3', '', '1', '2024-09-30 08:53:45', '1', '2024-09-30 08:55:01', b'0');
3214 3282 COMMIT;
3215 3283  
3216 3284 -- ----------------------------
... ... @@ -3235,7 +3303,7 @@ CREATE TABLE `system_sms_code` (
3235 3303 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
3236 3304 PRIMARY KEY (`id`) USING BTREE,
3237 3305 INDEX `idx_mobile`(`mobile` ASC) USING BTREE COMMENT '手机号'
3238   -) ENGINE = InnoDB AUTO_INCREMENT = 632 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '手机验证码';
  3306 +) ENGINE = InnoDB AUTO_INCREMENT = 642 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '手机验证码';
3239 3307  
3240 3308 -- ----------------------------
3241 3309 -- Records of system_sms_code
... ... @@ -3276,7 +3344,7 @@ CREATE TABLE `system_sms_log` (
3276 3344 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
3277 3345 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
3278 3346 PRIMARY KEY (`id`) USING BTREE
3279   -) ENGINE = InnoDB AUTO_INCREMENT = 1088 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信日志';
  3347 +) ENGINE = InnoDB AUTO_INCREMENT = 1234 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信日志';
3280 3348  
3281 3349 -- ----------------------------
3282 3350 -- Records of system_sms_log
... ... @@ -3315,7 +3383,7 @@ BEGIN;
3315 3383 INSERT INTO `system_sms_template` (`id`, `type`, `status`, `code`, `name`, `content`, `params`, `remark`, `api_template_id`, `channel_id`, `channel_code`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2, 1, 0, 'test_01', '测试验证码短信', '正在进行登录操作{operation},您的验证码是{code}', '[\"operation\",\"code\"]', '测试备注', '4383920', 4, 'DEBUG_DING_TALK', '', '2021-03-31 10:49:38', '1', '2024-08-18 11:57:18', b'0');
3316 3384 INSERT INTO `system_sms_template` (`id`, `type`, `status`, `code`, `name`, `content`, `params`, `remark`, `api_template_id`, `channel_id`, `channel_code`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3, 1, 0, 'test_02', '公告通知', '您的验证码{code},该验证码5分钟内有效,请勿泄漏于他人!', '[\"code\"]', NULL, 'SMS_207945135', 2, 'ALIYUN', '', '2021-03-31 11:56:30', '1', '2021-04-10 01:22:02', b'0');
3317 3385 INSERT INTO `system_sms_template` (`id`, `type`, `status`, `code`, `name`, `content`, `params`, `remark`, `api_template_id`, `channel_id`, `channel_code`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6, 3, 0, 'test-01', '测试模板', '哈哈哈 {name}', '[\"name\"]', 'f哈哈哈', '4383920', 4, 'DEBUG_DING_TALK', '1', '2021-04-10 01:07:21', '1', '2024-08-18 11:57:07', b'0');
3318   -INSERT INTO `system_sms_template` (`id`, `type`, `status`, `code`, `name`, `content`, `params`, `remark`, `api_template_id`, `channel_id`, `channel_code`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (7, 3, 0, 'test-04', '测试下', '老鸡{name},牛逼{code}', '[\"name\",\"code\"]', '哈哈哈哈', 'suibian', 4, 'DEBUG_DING_TALK', '1', '2021-04-13 00:29:53', '1', '2023-12-02 22:35:34', b'0');
  3386 +INSERT INTO `system_sms_template` (`id`, `type`, `status`, `code`, `name`, `content`, `params`, `remark`, `api_template_id`, `channel_id`, `channel_code`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (7, 3, 0, 'test-04', '测试下', '老鸡{name},牛逼{code}', '[\"name\",\"code\"]', '哈哈哈哈', 'suibian', 7, 'DEBUG_DING_TALK', '1', '2021-04-13 00:29:53', '1', '2024-09-30 00:56:24', b'0');
3319 3387 INSERT INTO `system_sms_template` (`id`, `type`, `status`, `code`, `name`, `content`, `params`, `remark`, `api_template_id`, `channel_id`, `channel_code`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (8, 1, 0, 'user-sms-login', '前台用户短信登录', '您的验证码是{code}', '[\"code\"]', NULL, '4372216', 4, 'DEBUG_DING_TALK', '1', '2021-10-11 08:10:00', '1', '2024-08-18 11:57:06', b'0');
3320 3388 INSERT INTO `system_sms_template` (`id`, `type`, `status`, `code`, `name`, `content`, `params`, `remark`, `api_template_id`, `channel_id`, `channel_code`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (9, 2, 0, 'bpm_task_assigned', '【工作流】任务被分配', '您收到了一条新的待办任务:{processInstanceName}-{taskName},申请人:{startUserNickname},处理链接:{detailUrl}', '[\"processInstanceName\",\"taskName\",\"startUserNickname\",\"detailUrl\"]', NULL, 'suibian', 4, 'DEBUG_DING_TALK', '1', '2022-01-21 22:31:19', '1', '2022-01-22 00:03:36', b'0');
3321 3389 INSERT INTO `system_sms_template` (`id`, `type`, `status`, `code`, `name`, `content`, `params`, `remark`, `api_template_id`, `channel_id`, `channel_code`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (10, 2, 0, 'bpm_process_instance_reject', '【工作流】流程被不通过', '您的流程被审批不通过:{processInstanceName},原因:{reason},查看链接:{detailUrl}', '[\"processInstanceName\",\"reason\",\"detailUrl\"]', NULL, 'suibian', 4, 'DEBUG_DING_TALK', '1', '2022-01-22 00:03:31', '1', '2022-05-01 12:33:14', b'0');
... ... @@ -3381,7 +3449,7 @@ CREATE TABLE `system_social_user` (
3381 3449 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
3382 3450 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
3383 3451 PRIMARY KEY (`id`) USING BTREE
3384   -) ENGINE = InnoDB AUTO_INCREMENT = 37 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交用户表';
  3452 +) ENGINE = InnoDB AUTO_INCREMENT = 38 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交用户表';
3385 3453  
3386 3454 -- ----------------------------
3387 3455 -- Records of system_social_user
... ... @@ -3406,7 +3474,7 @@ CREATE TABLE `system_social_user_bind` (
3406 3474 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
3407 3475 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
3408 3476 PRIMARY KEY (`id`) USING BTREE
3409   -) ENGINE = InnoDB AUTO_INCREMENT = 120 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交绑定表';
  3477 +) ENGINE = InnoDB AUTO_INCREMENT = 121 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社交绑定表';
3410 3478  
3411 3479 -- ----------------------------
3412 3480 -- Records of system_social_user_bind
... ... @@ -3443,7 +3511,7 @@ CREATE TABLE `system_tenant` (
3443 3511 BEGIN;
3444 3512 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');
3445 3513 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, '2025-03-11 00:00:00', 20, '1', '2022-02-22 00:56:14', '1', '2024-07-20 22:21:53', b'0');
3446   -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-07-20 15:51:18', b'0');
  3514 +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');
3447 3515 COMMIT;
3448 3516  
3449 3517 -- ----------------------------
... ... @@ -3518,7 +3586,7 @@ CREATE TABLE `system_user_role` (
3518 3586 `deleted` bit(1) NULL DEFAULT b'0' COMMENT '是否删除',
3519 3587 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
3520 3588 PRIMARY KEY (`id`) USING BTREE
3521   -) ENGINE = InnoDB AUTO_INCREMENT = 46 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户和角色关联表';
  3589 +) ENGINE = InnoDB AUTO_INCREMENT = 47 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户和角色关联表';
3522 3590  
3523 3591 -- ----------------------------
3524 3592 -- Records of system_user_role
... ... @@ -3539,6 +3607,7 @@ INSERT INTO `system_user_role` (`id`, `user_id`, `role_id`, `creator`, `create_t
3539 3607 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);
3540 3608 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);
3541 3609 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);
  3610 +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);
3542 3611 COMMIT;
3543 3612  
3544 3613 -- ----------------------------
... ... @@ -3567,16 +3636,16 @@ CREATE TABLE `system_users` (
3567 3636 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
3568 3637 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
3569 3638 PRIMARY KEY (`id`) USING BTREE
3570   -) ENGINE = InnoDB AUTO_INCREMENT = 139 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户信息表';
  3639 +) ENGINE = InnoDB AUTO_INCREMENT = 140 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户信息表';
3571 3640  
3572 3641 -- ----------------------------
3573 3642 -- Records of system_users
3574 3643 -- ----------------------------
3575 3644 BEGIN;
3576   -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$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '芋道源码', '管理员', 103, '[1,2]', 'aoteman@126.com', '18818260277', 2, 'http://test.yudao.iocoder.cn/bf2002b38950c904243be7c825d3f82e29f25a44526583c3fde2ebdff3a87f75.png', 0, '0:0:0:0:0:0:0:1', '2024-08-26 16:54:00', 'admin', '2021-01-05 17:03:47', NULL, '2024-08-26 16:54:00', b'0', 1);
3577   -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$10$11U48RhyJ5pSBYWSn12AD./ld671.ycSzJHbyrtpeoMeYiw31eo8a', '芋道', '不要吓我', 104, '[1]', 'yudao@iocoder.cn', '15601691300', 1, '', 0, '127.0.0.1', '2022-07-09 23:03:33', '', '2021-01-07 09:07:17', '1', '2024-08-17 11:06:13', b'0', 1);
  3645 +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$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '芋道源码', '管理员', 103, '[1,2]', 'aoteman@126.com', '18818260277', 2, 'http://test.yudao.iocoder.cn/bf2002b38950c904243be7c825d3f82e29f25a44526583c3fde2ebdff3a87f75.png', 0, '0:0:0:0:0:0:0:1', '2024-11-08 19:27:07', 'admin', '2021-01-05 17:03:47', NULL, '2024-11-08 19:27:07', b'0', 1);
  3646 +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$IgUse/ibRzAZ3rngCThmtemJeoh15Ux1TQ2hIMe4iwt/K3LcFHEda', '芋道', '不要吓我', 104, '[1]', 'yudao@iocoder.cn', '15601691300', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-11-02 14:00:46', '', '2021-01-07 09:07:17', NULL, '2024-11-02 14:00:46', b'0', 1);
3578 3647 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, '', 0, '0:0:0:0:0:0:0:1', '2024-08-11 17:48:12', '', '2021-01-13 23:50:35', NULL, '2024-08-11 17:48:12', b'0', 1);
3579   -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$jDFLttgfik0QqJKAbfhMa.2A9xXoZmAIxakdFJUzkX.MgBKT6ddo6', '测试号', NULL, 107, '[1,2]', '111@qq.com', '15601691200', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-08-11 09:38:08', '', '2021-01-21 02:13:53', NULL, '2024-08-11 09:38:08', b'0', 1);
  3648 +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$jDFLttgfik0QqJKAbfhMa.2A9xXoZmAIxakdFJUzkX.MgBKT6ddo6', '测试号', NULL, 107, '[1,2]', '111@qq.com', '15601691200', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-09-17 15:05:43', '', '2021-01-21 02:13:53', NULL, '2024-09-17 15:05:43', b'0', 1);
3580 3649 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, '', 0, '', NULL, '1', '2022-02-20 22:59:33', '1', '2022-02-27 08:26:51', b'0', 118);
3581 3650 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, '', 0, '', NULL, '1', '2022-02-20 23:00:50', '1', '2022-02-27 08:26:53', b'0', 119);
3582 3651 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 (109, 'admin109', '$2a$10$JAqvH0tEc0I7dfDVBI7zyuB4E3j.uH6daIjV53.vUS6PknFkDJkuK', '芋艿', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '', NULL, '1', '2022-02-20 23:11:50', '1', '2022-02-27 08:26:56', b'0', 120);
... ... @@ -3586,9 +3655,10 @@ INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`,
3586 3655 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', '芋道', NULL, NULL, NULL, '', '15601691300', 0, '', 0, '127.0.0.1', '2022-03-19 18:38:51', '1', '2022-03-07 21:37:58', NULL, '2022-03-19 18:38:51', b'0', 122);
3587 3656 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, '', 0, '0:0:0:0:0:0:0:1', '2024-03-24 22:21:05', '1', '2022-03-19 21:50:58', NULL, '2024-03-24 22:21:05', b'0', 1);
3588 3657 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, '', 0, '', NULL, '1', '2022-04-30 02:55:43', '1', '2024-04-04 09:37:14', b'0', 1);
3589   -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$10$WI8Gg/lpZQIrOEZMHqka7OdFaD4Nx.B/qY8ZGTTUKrOJwaHFqibaC', '测试号02', '1111', 100, '[2]', '', '15601691234', 1, '', 0, '', NULL, '1', '2022-07-09 17:40:26', '1', '2024-08-11 10:12:03', b'0', 1);
3590   -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$OB1SuphCdiLVRpiYRKeqH.8NYS7UIp5vmIv1W7U4w6toiFeOAATVK', '狗蛋', NULL, 103, '[1]', '', '15601691239', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-03-17 09:10:27', '1', '2022-07-09 17:44:43', '1', '2024-04-04 09:48:05', b'0', 1);
  3658 +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, '', 0, '0:0:0:0:0:0:0:1', '2024-10-02 10:16:20', '1', '2022-07-09 17:40:26', NULL, '2024-10-02 10:16:20', b'0', 1);
  3659 +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$OB1SuphCdiLVRpiYRKeqH.8NYS7UIp5vmIv1W7U4w6toiFeOAATVK', '狗蛋', NULL, 103, '[1]', '', '15601691239', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-03-17 09:10:27', '1', '2022-07-09 17:44:43', '1', '2024-09-06 21:40:43', b'0', 1);
3591 3660 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, '', 0, '', NULL, '1', '2024-04-27 08:45:56', '1', '2024-04-27 08:45:56', b'0', 1);
  3661 +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, '', 0, '0:0:0:0:0:0:0:1', '2024-09-10 21:03:58', NULL, '2024-09-10 21:03:58', NULL, '2024-09-10 21:03:58', b'0', 1);
3592 3662 COMMIT;
3593 3663  
3594 3664 -- ----------------------------
... ... @@ -3663,22 +3733,28 @@ CREATE TABLE `yudao_demo03_course` (
3663 3733 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
3664 3734 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
3665 3735 PRIMARY KEY (`id`) USING BTREE
3666   -) ENGINE = InnoDB AUTO_INCREMENT = 14 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '学生课程表';
  3736 +) ENGINE = InnoDB AUTO_INCREMENT = 20 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '学生课程表';
3667 3737  
3668 3738 -- ----------------------------
3669 3739 -- Records of yudao_demo03_course
3670 3740 -- ----------------------------
3671 3741 BEGIN;
3672   -INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, 2, '语文', 66, '1', '2023-11-16 23:21:49', '1', '2023-11-16 23:21:49', b'0', 1);
3673   -INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3, 2, '数学', 22, '1', '2023-11-16 23:21:49', '1', '2023-11-16 23:21:49', b'0', 1);
  3742 +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, 2, '语文', 66, '1', '2023-11-16 23:21:49', '1', '2024-09-17 10:55:30', b'1', 1);
  3743 +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3, 2, '数学', 22, '1', '2023-11-16 23:21:49', '1', '2024-09-17 10:55:30', b'1', 1);
3674 3744 INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6, 5, '体育', 23, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:44:40', b'1', 1);
3675 3745 INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (7, 5, '计算机', 11, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:44:40', b'1', 1);
3676 3746 INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (8, 5, '体育', 23, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:47:09', b'1', 1);
3677 3747 INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (9, 5, '计算机', 11, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:47:09', b'1', 1);
3678   -INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (10, 5, '体育', 23, '1', '2023-11-16 23:22:46', '1', '2023-11-16 23:47:10', b'0', 1);
3679   -INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (11, 5, '计算机', 11, '1', '2023-11-16 23:22:46', '1', '2023-11-16 23:47:10', b'0', 1);
  3748 +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (10, 5, '体育', 23, '1', '2023-11-16 23:22:46', '1', '2024-09-17 10:55:28', b'1', 1);
  3749 +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (11, 5, '计算机', 11, '1', '2023-11-16 23:22:46', '1', '2024-09-17 10:55:28', b'1', 1);
3680 3750 INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (12, 2, '电脑', 33, '1', '2023-11-17 00:20:42', '1', '2023-11-16 16:20:45', b'1', 1);
3681   -INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (13, 9, '滑雪', 12, '1', '2023-11-17 13:13:20', '1', '2023-11-17 13:13:20', b'0', 1);
  3751 +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (13, 9, '滑雪', 12, '1', '2023-11-17 13:13:20', '1', '2024-09-17 10:55:26', b'1', 1);
  3752 +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (14, 9, '滑雪', 12, '1', '2023-11-17 13:13:20', '1', '2024-09-17 10:55:49', b'1', 1);
  3753 +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (15, 5, '体育', 23, '1', '2023-11-16 23:22:46', '1', '2024-09-17 18:55:29', b'0', 1);
  3754 +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (16, 5, '计算机', 11, '1', '2023-11-16 23:22:46', '1', '2024-09-17 18:55:29', b'0', 1);
  3755 +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (17, 2, '语文', 66, '1', '2023-11-16 23:21:49', '1', '2024-09-17 18:55:31', b'0', 1);
  3756 +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (18, 2, '数学', 22, '1', '2023-11-16 23:21:49', '1', '2024-09-17 18:55:31', b'0', 1);
  3757 +INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (19, 9, '滑雪', 12, '1', '2023-11-17 13:13:20', '1', '2024-09-17 18:55:50', b'0', 1);
3682 3758 COMMIT;
3683 3759  
3684 3760 -- ----------------------------
... ... @@ -3703,9 +3779,9 @@ CREATE TABLE `yudao_demo03_grade` (
3703 3779 -- Records of yudao_demo03_grade
3704 3780 -- ----------------------------
3705 3781 BEGIN;
3706   -INSERT INTO `yudao_demo03_grade` (`id`, `student_id`, `name`, `teacher`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (7, 2, '三年 2 班', '周杰伦', '1', '2023-11-16 23:21:49', '1', '2023-11-16 23:21:49', b'0', 1);
3707   -INSERT INTO `yudao_demo03_grade` (`id`, `student_id`, `name`, `teacher`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (8, 5, '华为', '遥遥领先', '1', '2023-11-16 23:22:46', '1', '2023-11-16 23:47:10', b'0', 1);
3708   -INSERT INTO `yudao_demo03_grade` (`id`, `student_id`, `name`, `teacher`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (9, 9, '小图', '小娃111', '1', '2023-11-17 13:10:23', '1', '2023-11-17 13:10:23', b'0', 1);
  3782 +INSERT INTO `yudao_demo03_grade` (`id`, `student_id`, `name`, `teacher`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (7, 2, '三年 2 班', '周杰伦', '1', '2023-11-16 23:21:49', '1', '2024-09-17 18:55:31', b'0', 1);
  3783 +INSERT INTO `yudao_demo03_grade` (`id`, `student_id`, `name`, `teacher`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (8, 5, '华为', '遥遥领先', '1', '2023-11-16 23:22:46', '1', '2024-09-17 18:55:29', b'0', 1);
  3784 +INSERT INTO `yudao_demo03_grade` (`id`, `student_id`, `name`, `teacher`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (9, 9, '小图', '小娃111', '1', '2023-11-17 13:10:23', '1', '2024-09-17 18:55:50', b'0', 1);
3709 3785 COMMIT;
3710 3786  
3711 3787 -- ----------------------------
... ... @@ -3731,9 +3807,9 @@ CREATE TABLE `yudao_demo03_student` (
3731 3807 -- Records of yudao_demo03_student
3732 3808 -- ----------------------------
3733 3809 BEGIN;
3734   -INSERT INTO `yudao_demo03_student` (`id`, `name`, `sex`, `birthday`, `description`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, '小白', 1, '2023-11-16 00:00:00', '<p>厉害</p>', '1', '2023-11-16 23:21:49', '1', '2023-11-17 16:49:06', b'0', 1);
3735   -INSERT INTO `yudao_demo03_student` (`id`, `name`, `sex`, `birthday`, `description`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5, '大黑', 2, '2023-11-13 00:00:00', '<p>你在教我做事?</p>', '1', '2023-11-16 23:22:46', '1', '2023-11-17 16:49:07', b'0', 1);
3736   -INSERT INTO `yudao_demo03_student` (`id`, `name`, `sex`, `birthday`, `description`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (9, '小花', 1, '2023-11-07 00:00:00', '<p>哈哈哈</p>', '1', '2023-11-17 00:04:47', '1', '2023-11-17 16:49:08', b'0', 1);
  3810 +INSERT INTO `yudao_demo03_student` (`id`, `name`, `sex`, `birthday`, `description`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, '小白', 1, '2023-11-16 00:00:00', '<p>厉害</p>', '1', '2023-11-16 23:21:49', '1', '2024-09-17 18:55:31', b'0', 1);
  3811 +INSERT INTO `yudao_demo03_student` (`id`, `name`, `sex`, `birthday`, `description`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5, '大黑', 2, '2023-11-13 00:00:00', '<p>你在教我做事?</p>', '1', '2023-11-16 23:22:46', '1', '2024-09-17 18:55:29', b'0', 1);
  3812 +INSERT INTO `yudao_demo03_student` (`id`, `name`, `sex`, `birthday`, `description`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (9, '小花', 1, '2023-11-07 00:00:00', '<p>哈哈哈</p>', '1', '2023-11-17 00:04:47', '1', '2024-09-17 18:55:50', b'0', 1);
3737 3813 COMMIT;
3738 3814  
3739 3815 SET FOREIGN_KEY_CHECKS = 1;
... ...
sql/postgresql/ruoyi-vue-pro.sql
... ... @@ -1126,6 +1126,55 @@ INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_t
1126 1126 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 (1534, 1, '赢单', '1', 'crm_business_end_status_type', 0, 'success', '', '', '1', '2024-04-13 23:26:57', '1', '2024-04-13 23:26:57', '0');
1127 1127 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 (1535, 2, '输单', '2', 'crm_business_end_status_type', 0, 'primary', '', '', '1', '2024-04-13 23:27:31', '1', '2024-04-13 23:27:31', '0');
1128 1128 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 (1536, 3, '无效', '3', 'crm_business_end_status_type', 0, 'info', '', '', '1', '2024-04-13 23:27:59', '1', '2024-04-13 23:27:59', '0');
  1129 +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 (1537, 1, 'OpenAI', 'OpenAI', 'ai_platform', 0, '', '', '', '1', '2024-05-09 22:33:47', '1', '2024-05-09 22:58:46', '0');
  1130 +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 (1538, 2, 'Ollama', 'Ollama', 'ai_platform', 0, '', '', '', '1', '2024-05-17 23:02:55', '1', '2024-05-17 23:02:55', '0');
  1131 +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 (1539, 3, '文心一言', 'YiYan', 'ai_platform', 0, '', '', '', '1', '2024-05-18 09:24:20', '1', '2024-05-18 09:29:01', '0');
  1132 +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 (1540, 4, '讯飞星火', 'XingHuo', 'ai_platform', 0, '', '', '', '1', '2024-05-18 10:08:56', '1', '2024-05-18 10:08:56', '0');
  1133 +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 (1541, 5, '通义千问', 'TongYi', 'ai_platform', 0, '', '', '', '1', '2024-05-18 10:32:29', '1', '2024-07-06 15:42:29', '0');
  1134 +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 (1542, 6, 'StableDiffusion', 'StableDiffusion', 'ai_platform', 0, '', '', '', '1', '2024-06-01 15:09:31', '1', '2024-06-01 15:10:25', '0');
  1135 +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 (1543, 10, '进行中', '10', 'ai_image_status', 0, 'primary', '', '', '1', '2024-06-26 20:51:41', '1', '2024-06-26 20:52:48', '0');
  1136 +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 (1544, 20, '已完成', '20', 'ai_image_status', 0, 'success', '', '', '1', '2024-06-26 20:52:07', '1', '2024-06-26 20:52:41', '0');
  1137 +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 (1545, 30, '已失败', '30', 'ai_image_status', 0, 'warning', '', '', '1', '2024-06-26 20:52:25', '1', '2024-06-26 20:52:35', '0');
  1138 +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 (1546, 7, 'Midjourney', 'Midjourney', 'ai_platform', 0, '', '', '', '1', '2024-06-26 22:14:46', '1', '2024-06-26 22:14:46', '0');
  1139 +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 (1547, 10, '进行中', '10', 'ai_music_status', 0, 'primary', '', '', '1', '2024-06-27 22:45:22', '1', '2024-06-28 00:56:17', '0');
  1140 +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 (1548, 20, '已完成', '20', 'ai_music_status', 0, 'success', '', '', '1', '2024-06-27 22:45:33', '1', '2024-06-28 00:56:18', '0');
  1141 +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 (1549, 30, '已失败', '30', 'ai_music_status', 0, 'danger', '', '', '1', '2024-06-27 22:45:44', '1', '2024-06-28 00:56:19', '0');
  1142 +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 (1550, 1, '歌词模式', '1', 'ai_generate_mode', 0, '', '', '', '1', '2024-06-27 22:46:31', '1', '2024-06-28 01:22:25', '0');
  1143 +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 (1551, 2, '描述模式', '2', 'ai_generate_mode', 0, '', '', '', '1', '2024-06-27 22:46:37', '1', '2024-06-28 01:22:24', '0');
  1144 +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 (1552, 8, 'Suno', 'Suno', 'ai_platform', 0, '', '', '', '1', '2024-06-29 09:13:36', '1', '2024-06-29 09:13:41', '0');
  1145 +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 (1553, 9, 'DeepSeek', 'DeepSeek', 'ai_platform', 0, '', '', '', '1', '2024-07-06 12:04:30', '1', '2024-07-06 12:05:20', '0');
  1146 +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 (1554, 10, '智谱', 'ZhiPu', 'ai_platform', 0, '', '', '', '1', '2024-07-06 18:00:35', '1', '2024-07-06 18:00:35', '0');
  1147 +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 (1555, 4, '长', '4', 'ai_write_length', 0, '', '', '', '1', '2024-07-07 15:49:03', '1', '2024-07-07 15:49:03', '0');
  1148 +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 (1556, 5, '段落', '5', 'ai_write_format', 0, '', '', '', '1', '2024-07-07 15:49:54', '1', '2024-07-07 15:49:54', '0');
  1149 +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 (1557, 6, '文章', '6', 'ai_write_format', 0, '', '', '', '1', '2024-07-07 15:50:05', '1', '2024-07-07 15:50:05', '0');
  1150 +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 (1558, 7, '博客文章', '7', 'ai_write_format', 0, '', '', '', '1', '2024-07-07 15:50:23', '1', '2024-07-07 15:50:23', '0');
  1151 +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 (1559, 8, '想法', '8', 'ai_write_format', 0, '', '', '', '1', '2024-07-07 15:50:31', '1', '2024-07-07 15:50:31', '0');
  1152 +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 (1560, 9, '大纲', '9', 'ai_write_format', 0, '', '', '', '1', '2024-07-07 15:50:37', '1', '2024-07-07 15:50:37', '0');
  1153 +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 (1561, 1, '自动', '1', 'ai_write_tone', 0, '', '', '', '1', '2024-07-07 15:51:06', '1', '2024-07-07 15:51:06', '0');
  1154 +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 (1562, 2, '友善', '2', 'ai_write_tone', 0, '', '', '', '1', '2024-07-07 15:51:19', '1', '2024-07-07 15:51:19', '0');
  1155 +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 (1563, 3, '随意', '3', 'ai_write_tone', 0, '', '', '', '1', '2024-07-07 15:51:27', '1', '2024-07-07 15:51:27', '0');
  1156 +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 (1564, 4, '友好', '4', 'ai_write_tone', 0, '', '', '', '1', '2024-07-07 15:51:37', '1', '2024-07-07 15:51:37', '0');
  1157 +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 (1565, 5, '专业', '5', 'ai_write_tone', 0, '', '', '', '1', '2024-07-07 15:51:49', '1', '2024-07-07 15:52:02', '0');
  1158 +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 (1566, 6, '诙谐', '6', 'ai_write_tone', 0, '', '', '', '1', '2024-07-07 15:52:15', '1', '2024-07-07 15:52:15', '0');
  1159 +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 (1567, 7, '有趣', '7', 'ai_write_tone', 0, '', '', '', '1', '2024-07-07 15:52:24', '1', '2024-07-07 15:52:24', '0');
  1160 +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 (1568, 8, '正式', '8', 'ai_write_tone', 0, '', '', '', '1', '2024-07-07 15:54:33', '1', '2024-07-07 15:54:33', '0');
  1161 +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 (1569, 5, '段落', '5', 'ai_write_format', 0, '', '', '', '1', '2024-07-07 15:49:54', '1', '2024-07-07 15:49:54', '0');
  1162 +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 (1570, 1, '自动', '1', 'ai_write_format', 0, '', '', '', '1', '2024-07-07 15:19:34', '1', '2024-07-07 15:19:34', '0');
  1163 +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 (1571, 2, '电子邮件', '2', 'ai_write_format', 0, '', '', '', '1', '2024-07-07 15:19:50', '1', '2024-07-07 15:49:30', '0');
  1164 +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 (1572, 3, '消息', '3', 'ai_write_format', 0, '', '', '', '1', '2024-07-07 15:20:01', '1', '2024-07-07 15:49:38', '0');
  1165 +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 (1573, 4, '评论', '4', 'ai_write_format', 0, '', '', '', '1', '2024-07-07 15:20:13', '1', '2024-07-07 15:49:45', '0');
  1166 +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 (1574, 1, '自动', '1', 'ai_write_language', 0, '', '', '', '1', '2024-07-07 15:44:18', '1', '2024-07-07 15:44:18', '0');
  1167 +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 (1575, 2, '中文', '2', 'ai_write_language', 0, '', '', '', '1', '2024-07-07 15:44:28', '1', '2024-07-07 15:44:28', '0');
  1168 +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 (1576, 3, '英文', '3', 'ai_write_language', 0, '', '', '', '1', '2024-07-07 15:44:37', '1', '2024-07-07 15:44:37', '0');
  1169 +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 (1577, 4, '韩语', '4', 'ai_write_language', 0, '', '', '', '1', '2024-07-07 15:46:28', '1', '2024-07-07 15:46:28', '0');
  1170 +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 (1578, 5, '日语', '5', 'ai_write_language', 0, '', '', '', '1', '2024-07-07 15:46:44', '1', '2024-07-07 15:46:44', '0');
  1171 +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 (1579, 1, '自动', '1', 'ai_write_length', 0, '', '', '', '1', '2024-07-07 15:48:34', '1', '2024-07-07 15:48:34', '0');
  1172 +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 (1580, 2, '短', '2', 'ai_write_length', 0, '', '', '', '1', '2024-07-07 15:48:44', '1', '2024-07-07 15:48:44', '0');
  1173 +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 (1581, 3, '中等', '3', 'ai_write_length', 0, '', '', '', '1', '2024-07-07 15:48:52', '1', '2024-07-07 15:48:52', '0');
  1174 +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 (1582, 4, '长', '4', 'ai_write_length', 0, '', '', '', '1', '2024-07-07 15:49:03', '1', '2024-07-07 15:49:03', '0');
  1175 +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 (1584, 1, '撰写', '1', 'ai_write_type', 0, '', '', '', '1', '2024-07-10 21:26:00', '1', '2024-07-10 21:26:00', '0');
  1176 +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 (1585, 2, '回复', '2', 'ai_write_type', 0, '', '', '', '1', '2024-07-10 21:26:06', '1', '2024-07-10 21:26:06', '0');
  1177 +
1129 1178 COMMIT;
1130 1179 -- @formatter:on
1131 1180  
... ... @@ -2328,6 +2377,54 @@ INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon
2328 2377 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 (2755, '删除项目', 'report:go-view-project:delete', 3, 2, 2153, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 20:01:37', '1', '2024-04-24 20:01:37', '0');
2329 2378 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 (2756, '会员等级记录查询', 'member:level-record:query', 3, 10, 2325, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 20:02:32', '1', '2024-04-24 20:02:32', '0');
2330 2379 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 (2757, '会员经验记录查询', 'member:experience-record:query', 3, 11, 2325, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 20:02:51', '1', '2024-04-24 20:02:51', '0');
  2380 +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 (2758, 'AI 大模型', '', 1, 400, 0, '/ai', 'fa:apple', '', '', 0, '1', '1', '1', '1', '2024-05-07 15:07:56', '1', '2024-05-25 12:36:12', '0');
  2381 +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 (2759, 'AI 对话', '', 2, 1, 2758, 'chat', 'ep:message', 'ai/chat/index/index.vue', 'AiChat', 0, '1', '1', '1', '1', '2024-05-07 15:09:14', '1', '2024-07-07 17:15:36', '0');
  2382 +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 (2760, '控制台', '', 1, 100, 2758, 'console', 'ep:setting', '', '', 0, '1', '1', '1', '1', '2024-05-09 22:39:09', '1', '2024-05-24 23:34:21', '0');
  2383 +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 (2761, 'API 密钥', '', 2, 0, 2760, 'api-key', 'ep:key', 'ai/model/apiKey/index.vue', 'AiApiKey', 0, '1', '1', '1', '', '2024-05-09 14:52:56', '1', '2024-05-10 22:44:08', '0');
  2384 +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 (2762, 'API 密钥查询', 'ai:api-key:query', 3, 1, 2761, '', '', '', '', 0, '1', '1', '1', '', '2024-05-09 14:52:56', '1', '2024-05-13 20:36:32', '0');
  2385 +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 (2763, 'API 密钥创建', 'ai:api-key:create', 3, 2, 2761, '', '', '', '', 0, '1', '1', '1', '', '2024-05-09 14:52:56', '1', '2024-05-13 20:36:26', '0');
  2386 +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 (2764, 'API 密钥更新', 'ai:api-key:update', 3, 3, 2761, '', '', '', '', 0, '1', '1', '1', '', '2024-05-09 14:52:56', '1', '2024-05-13 20:36:42', '0');
  2387 +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 (2765, 'API 密钥删除', 'ai:api-key:delete', 3, 4, 2761, '', '', '', '', 0, '1', '1', '1', '', '2024-05-09 14:52:56', '1', '2024-05-13 20:36:48', '0');
  2388 +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 (2767, '聊天模型', '', 2, 0, 2760, 'chat-model', 'fa-solid:abacus', 'ai/model/chatModel/index.vue', 'AiChatModel', 0, '1', '1', '1', '', '2024-05-10 14:42:48', '1', '2024-05-10 22:44:16', '0');
  2389 +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 (2768, '聊天模型查询', 'ai:chat-model:query', 3, 1, 2767, '', '', '', '', 0, '1', '1', '1', '', '2024-05-10 14:42:48', '1', '2024-05-13 20:37:02', '0');
  2390 +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 (2769, '聊天模型创建', 'ai:chat-model:create', 3, 2, 2767, '', '', '', '', 0, '1', '1', '1', '', '2024-05-10 14:42:48', '1', '2024-05-13 20:37:12', '0');
  2391 +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 (2770, '聊天模型更新', 'ai:chat-model:update', 3, 3, 2767, '', '', '', '', 0, '1', '1', '1', '', '2024-05-10 14:42:48', '1', '2024-05-13 20:37:18', '0');
  2392 +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 (2771, '聊天模型删除', 'ai:chat-model:delete', 3, 4, 2767, '', '', '', '', 0, '1', '1', '1', '', '2024-05-10 14:42:48', '1', '2024-05-13 20:37:23', '0');
  2393 +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 (2773, '聊天角色', '', 2, 0, 2760, 'chat-role', 'fa:user-secret', 'ai/model/chatRole/index.vue', 'AiChatRole', 0, '1', '1', '1', '', '2024-05-13 12:39:28', '1', '2024-05-13 20:41:45', '0');
  2394 +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 (2774, '聊天角色查询', 'ai:chat-role:query', 3, 1, 2773, '', '', '', NULL, 0, '1', '1', '1', '', '2024-05-13 12:39:28', '', '2024-05-13 12:39:28', '0');
  2395 +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 (2775, '聊天角色创建', 'ai:chat-role:create', 3, 2, 2773, '', '', '', NULL, 0, '1', '1', '1', '', '2024-05-13 12:39:28', '', '2024-05-13 12:39:28', '0');
  2396 +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 (2776, '聊天角色更新', 'ai:chat-role:update', 3, 3, 2773, '', '', '', NULL, 0, '1', '1', '1', '', '2024-05-13 12:39:28', '', '2024-05-13 12:39:28', '0');
  2397 +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 (2777, '聊天角色删除', 'ai:chat-role:delete', 3, 4, 2773, '', '', '', '', 0, '1', '1', '1', '1', '2024-05-13 21:43:38', '1', '2024-05-13 21:43:38', '0');
  2398 +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 (2778, '聊天管理', '', 2, 10, 2760, 'chat-conversation', 'ep:chat-square', 'ai/chat/manager/index.vue', 'AiChatManager', 0, '1', '1', '1', '', '2024-05-24 15:39:18', '1', '2024-06-26 21:36:56', '0');
  2399 +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 (2779, '会话查询', 'ai:chat-conversation:query', 3, 1, 2778, '', '', '', '', 0, '1', '1', '1', '', '2024-05-24 15:39:18', '1', '2024-05-25 08:38:30', '0');
  2400 +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 (2780, '会话删除', 'ai:chat-conversation:delete', 3, 2, 2778, '', '', '', '', 0, '1', '1', '1', '', '2024-05-24 15:39:18', '1', '2024-05-25 08:38:40', '0');
  2401 +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 (2781, '消息查询', 'ai:chat-message:query', 3, 11, 2778, '', '', '', '', 0, '1', '1', '1', '1', '2024-05-25 08:38:56', '1', '2024-05-25 08:38:56', '0');
  2402 +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 (2782, '消息删除', 'ai:chat-message:delete', 3, 12, 2778, '', '', '', '', 0, '1', '1', '1', '1', '2024-05-25 08:39:10', '1', '2024-05-25 08:39:10', '0');
  2403 +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 (2783, 'AI 绘画', '', 2, 2, 2758, 'image', 'ep:picture-rounded', 'ai/image/index/index.vue', 'AiImage', 0, '1', '1', '1', '1', '2024-05-26 11:45:17', '1', '2024-07-07 17:18:59', '0');
  2404 +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 (2784, '绘画管理', '', 2, 11, 2760, 'image', 'fa:file-image-o', 'ai/image/manager/index.vue', 'AiImageManager', 0, '1', '1', '1', '', '2024-06-26 13:32:31', '1', '2024-06-26 21:37:13', '0');
  2405 +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 (2785, '绘画查询', 'ai:image:query', 3, 1, 2784, '', '', '', '', 0, '1', '1', '1', '', '2024-06-26 13:32:31', '1', '2024-06-26 22:21:57', '0');
  2406 +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 (2786, '绘画删除', 'ai:image:delete', 3, 4, 2784, '', '', '', '', 0, '1', '1', '1', '', '2024-06-26 13:32:31', '1', '2024-06-26 22:22:08', '0');
  2407 +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 (2787, '绘图更新', 'ai:image:update', 3, 2, 2784, '', '', '', '', 0, '1', '1', '1', '1', '2024-06-26 22:47:56', '1', '2024-08-31 09:21:35', '0');
  2408 +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 (2788, '音乐管理', '', 2, 12, 2760, 'music', 'fa:music', 'ai/music/manager/index.vue', 'AiMusicManager', 0, '1', '1', '1', '', '2024-06-27 15:03:33', '1', '2024-06-27 23:04:19', '0');
  2409 +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 (2789, '音乐查询', 'ai:music:query', 3, 1, 2788, '', '', '', NULL, 0, '1', '1', '1', '', '2024-06-27 15:03:33', '', '2024-06-27 15:03:33', '0');
  2410 +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 (2790, '音乐更新', 'ai:music:update', 3, 3, 2788, '', '', '', NULL, 0, '1', '1', '1', '', '2024-06-27 15:03:33', '', '2024-06-27 15:03:33', '0');
  2411 +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 (2791, '音乐删除', 'ai:music:delete', 3, 4, 2788, '', '', '', NULL, 0, '1', '1', '1', '', '2024-06-27 15:03:33', '', '2024-06-27 15:03:33', '0');
  2412 +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 (2792, 'AI 写作', '', 2, 3, 2758, 'write', 'fa-solid:book-reader', 'ai/write/index/index.vue', 'AiWrite', 0, '1', '1', '1', '1', '2024-07-08 09:26:44', '1', '2024-07-16 13:03:06', '0');
  2413 +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 (2793, '写作管理', '', 2, 13, 2760, 'write', 'fa:bookmark-o', 'ai/write/manager/index.vue', 'AiWriteManager', 0, '1', '1', '1', '', '2024-07-10 13:24:34', '1', '2024-07-10 21:31:59', '0');
  2414 +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 (2794, 'AI 写作查询', 'ai:write:query', 3, 1, 2793, '', '', '', NULL, 0, '1', '1', '1', '', '2024-07-10 13:24:34', '', '2024-07-10 13:24:34', '0');
  2415 +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 (2795, 'AI 写作删除', 'ai:write:delete', 3, 4, 2793, '', '', '', NULL, 0, '1', '1', '1', '', '2024-07-10 13:24:34', '', '2024-07-10 13:24:34', '0');
  2416 +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 (2796, 'AI 音乐', '', 2, 4, 2758, 'music', 'fa:music', 'ai/music/index/index.vue', 'AiMusic', 0, '1', '1', '1', '1', '2024-07-17 09:21:12', '1', '2024-07-29 21:11:52', '0');
  2417 +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 (2797, '客服中心', '', 2, 100, 2362, 'kefu', 'fa-solid:user-alt', 'mall/promotion/kefu/index', 'KeFu', 0, '1', '1', '1', '1', '2024-07-17 23:49:05', '1', '2024-07-17 23:49:16', '0');
  2418 +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 (2798, 'AI 思维导图', '', 2, 5, 2758, 'mind-map', 'fa:sitemap', 'ai/mindmap/index/index.vue', 'AiMindMap', 0, '1', '1', '1', '1', '2024-07-29 21:31:59', '1', '2024-07-29 21:33:20', '0');
  2419 +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 (2799, '导图管理', '', 2, 14, 2760, 'mind-map', 'fa:map', 'ai/mindmap/manager/index', 'AiMindMapManager', 0, '1', '1', '1', '', '2024-08-10 09:15:09', '1', '2024-08-10 17:24:28', '0');
  2420 +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 (2800, '思维导图查询', 'ai:mind-map:query', 3, 1, 2799, '', '', '', NULL, 0, '1', '1', '1', '', '2024-08-10 09:15:09', '', '2024-08-10 09:15:09', '0');
  2421 +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 (2801, '思维导图删除', 'ai:mind-map:delete', 3, 4, 2799, '', '', '', NULL, 0, '1', '1', '1', '', '2024-08-10 09:15:09', '', '2024-08-10 09:15:09', '0');
  2422 +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 (2802, '会话查询', 'promotion:kefu-conversation:query', 3, 1, 2797, '', '', '', '', 0, '1', '1', '1', '1', '2024-08-31 09:17:52', '1', '2024-08-31 09:18:52', '0');
  2423 +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 (2803, '会话更新', 'promotion:kefu-conversation:update', 3, 2, 2797, '', '', '', '', 0, '1', '1', '1', '1', '2024-08-31 09:18:15', '1', '2024-08-31 09:19:29', '0');
  2424 +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 (2804, '消息查询', 'promotion:kefu-message:query', 3, 10, 2797, '', '', '', '', 0, '1', '1', '1', '1', '2024-08-31 09:18:42', '1', '2024-08-31 09:18:42', '0');
  2425 +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 (2805, '会话删除', 'promotion:kefu-conversation:delete', 3, 3, 2797, '', '', '', '', 0, '1', '1', '1', '1', '2024-08-31 09:19:51', '1', '2024-08-31 09:20:32', '0');
  2426 +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 (2806, '消息发送', 'promotion:kefu-message:send', 3, 12, 2797, '', '', '', '', 0, '1', '1', '1', '1', '2024-08-31 09:20:06', '1', '2024-08-31 09:20:06', '0');
  2427 +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 (2807, '消息更新', 'promotion:kefu-message:update', 3, 11, 2797, '', '', '', '', 0, '1', '1', '1', '1', '2024-08-31 09:20:22', '1', '2024-08-31 09:20:22', '0');
2331 2428 COMMIT;
2332 2429 -- @formatter:on
2333 2430  
... ...
yudao-dependencies/pom.xml
... ... @@ -14,7 +14,7 @@
14 14 <url>https://github.com/YunaiV/ruoyi-vue-pro</url>
15 15  
16 16 <properties>
17   - <revision>2.2.0-SNAPSHOT</revision>
  17 + <revision>2.3.0-SNAPSHOT</revision>
18 18 <flatten-maven-plugin.version>1.6.0</flatten-maven-plugin.version>
19 19 <!-- 统一依赖管理 -->
20 20 <spring.boot.version>3.3.4</spring.boot.version>
... ... @@ -66,14 +66,12 @@
66 66 <netty.version>4.1.113.Final</netty.version>
67 67 <mqtt.version>1.2.5</mqtt.version>
68 68 <!-- 三方云服务相关 -->
69   - <okio.version>3.5.0</okio.version>
70   - <okhttp3.version>4.11.0</okhttp3.version>
71 69 <commons-io.version>2.17.0</commons-io.version>
72 70 <commons-compress.version>1.27.1</commons-compress.version>
73   - <minio.version>8.5.7</minio.version>
  71 + <aws-java-sdk-s3.version>1.12.777</aws-java-sdk-s3.version>
74 72 <justauth.version>2.0.5</justauth.version>
75 73 <jimureport.version>1.8.1</jimureport.version>
76   - <weixin-java.version>4.6.5.B</weixin-java.version>
  74 + <weixin-java.version>4.6.0</weixin-java.version>
77 75 </properties>
78 76  
79 77 <dependencyManagement>
... ... @@ -542,19 +540,9 @@
542 540  
543 541 <!-- 三方云服务相关 -->
544 542 <dependency>
545   - <groupId>com.squareup.okio</groupId>
546   - <artifactId>okio</artifactId>
547   - <version>${okio.version}</version>
548   - </dependency>
549   - <dependency>
550   - <groupId>com.squareup.okhttp3</groupId>
551   - <artifactId>okhttp</artifactId>
552   - <version>${okhttp3.version}</version>
553   - </dependency>
554   - <dependency>
555   - <groupId>io.minio</groupId>
556   - <artifactId>minio</artifactId>
557   - <version>${minio.version}</version>
  543 + <groupId>com.amazonaws</groupId>
  544 + <artifactId>aws-java-sdk-s3</artifactId>
  545 + <version>${aws-java-sdk-s3.version}</version>
558 546 </dependency>
559 547  
560 548 <dependency>
... ...
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java
... ... @@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
4 4 import cn.iocoder.yudao.framework.tenant.config.TenantProperties;
5 5 import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
6 6 import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
  7 +import com.baomidou.mybatisplus.extension.toolkit.SqlParserUtils;
7 8 import net.sf.jsqlparser.expression.Expression;
8 9 import net.sf.jsqlparser.expression.LongValue;
9 10  
... ... @@ -37,7 +38,7 @@ public class TenantDatabaseInterceptor implements TenantLineHandler {
37 38 @Override
38 39 public boolean ignoreTable(String tableName) {
39 40 return TenantContextHolder.isIgnore() // 情况一,全局忽略多租户
40   - || CollUtil.contains(ignoreTables, tableName); // 情况二,忽略多租户的表
  41 + || CollUtil.contains(ignoreTables, SqlParserUtils.removeWrapperSymbol(tableName)); // 情况二,忽略多租户的表
41 42 }
42 43  
43 44 }
... ...
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJobAspect.java
... ... @@ -46,7 +46,7 @@ public class TenantJobAspect {
46 46 TenantUtils.execute(tenantId, () -> {
47 47 try {
48 48 Object result = joinPoint.proceed();
49   - results.put(tenantId, StrUtil.toStringOrNull(result));
  49 + results.put(tenantId, StrUtil.toStringOrEmpty(result));
50 50 } catch (Throwable e) {
51 51 log.error("[execute][租户({}) 执行 Job 发生异常", tenantId, e);
52 52 results.put(tenantId, ExceptionUtil.getRootCauseMessage(e));
... ...
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java
... ... @@ -36,8 +36,9 @@ public class MyBatisUtils {
36 36 Page<T> page = new Page<>(pageParam.getPageNo(), pageParam.getPageSize());
37 37 // 排序字段
38 38 if (!CollectionUtil.isEmpty(sortingFields)) {
39   - page.addOrder(sortingFields.stream().map(sortingField -> SortingField.ORDER_ASC.equals(sortingField.getOrder()) ?
40   - OrderItem.asc(sortingField.getField()) : OrderItem.desc(sortingField.getField()))
  39 + page.addOrder(sortingFields.stream().map(sortingField -> SortingField.ORDER_ASC.equals(sortingField.getOrder())
  40 + ? OrderItem.asc(StrUtil.toUnderlineCase(sortingField.getField()))
  41 + : OrderItem.desc(StrUtil.toUnderlineCase(sortingField.getField())))
41 42 .collect(Collectors.toList()));
42 43 }
43 44 return page;
... ...
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/desensitize/core/slider/handler/AbstractSliderDesensitizationHandler.java
... ... @@ -17,7 +17,7 @@ public abstract class AbstractSliderDesensitizationHandler&lt;T extends Annotation&gt;
17 17 public String desensitize(String origin, T annotation) {
18 18 // 1. 判断是否禁用脱敏
19 19 Object disable = SpringExpressionUtils.parseExpression(getDisable(annotation));
20   - if (Boolean.FALSE.equals(disable)) {
  20 + if (Boolean.TRUE.equals(disable)) {
21 21 return origin;
22 22 }
23 23  
... ...
yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/sender/AbstractWebSocketMessageSender.java
... ... @@ -64,8 +64,10 @@ public abstract class AbstractWebSocketMessageSender implements WebSocketMessage
64 64 sessions = (List<WebSocketSession>) sessionManager.getSessionList(userType);
65 65 }
66 66 if (CollUtil.isEmpty(sessions)) {
67   - log.info("[send][sessionId({}) userType({}) userId({}) messageType({}) messageContent({}) 未匹配到会话]",
68   - sessionId, userType, userId, messageType, messageContent);
  67 + if (log.isDebugEnabled()) {
  68 + log.debug("[send][sessionId({}) userType({}) userId({}) messageType({}) messageContent({}) 未匹配到会话]",
  69 + sessionId, userType, userId, messageType, messageContent);
  70 + }
69 71 }
70 72 // 2. 执行发送
71 73 doSend(sessions, messageType, messageContent);
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/AiImageController.java
... ... @@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi;
5 5 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
6 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 7 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  8 +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
8 9 import cn.iocoder.yudao.module.ai.controller.admin.image.vo.*;
9 10 import cn.iocoder.yudao.module.ai.controller.admin.image.vo.midjourney.AiMidjourneyActionReqVO;
10 11 import cn.iocoder.yudao.module.ai.controller.admin.image.vo.midjourney.AiMidjourneyImagineReqVO;
... ... @@ -95,6 +96,7 @@ public class AiImageController {
95 96 @Operation(summary = "【Midjourney】通知图片进展", description = "由 Midjourney Proxy 回调")
96 97 @PostMapping("/midjourney/notify") // 必须是 POST 方法,否则会报错
97 98 @PermitAll
  99 + @TenantIgnore
98 100 public CommonResult<Boolean> midjourneyNotify(@Valid @RequestBody MidjourneyApi.Notify notify) {
99 101 imageService.midjourneyNotify(notify);
100 102 return success(true);
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/image/AiImageDO.java
... ... @@ -5,7 +5,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
5 5 import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO;
6 6 import cn.iocoder.yudao.module.ai.enums.image.AiImageStatusEnum;
7 7 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
8   -import com.baomidou.mybatisplus.annotation.IdType;
  8 +import com.baomidou.mybatisplus.annotation.KeySequence;
9 9 import com.baomidou.mybatisplus.annotation.TableField;
10 10 import com.baomidou.mybatisplus.annotation.TableId;
11 11 import com.baomidou.mybatisplus.annotation.TableName;
... ... @@ -24,6 +24,7 @@ import java.util.Map;
24 24 * @author fansili
25 25 */
26 26 @TableName(value = "ai_image", autoResultMap = true)
  27 +@KeySequence("ai_image_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
27 28 @Data
28 29 public class AiImageDO extends BaseDO {
29 30  
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/knowledge/AiKnowledgeDO.java
... ... @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.ai.dal.dataobject.knowledge;
3 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 4 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
5 5 import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler;
  6 +import com.baomidou.mybatisplus.annotation.KeySequence;
6 7 import com.baomidou.mybatisplus.annotation.TableField;
7 8 import com.baomidou.mybatisplus.annotation.TableId;
8 9 import com.baomidou.mybatisplus.annotation.TableName;
... ... @@ -16,6 +17,7 @@ import java.util.List;
16 17 * @author xiaoxin
17 18 */
18 19 @TableName(value = "ai_knowledge", autoResultMap = true)
  20 +@KeySequence("ai_knowledge_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
19 21 @Data
20 22 public class AiKnowledgeDO extends BaseDO {
21 23  
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/knowledge/AiKnowledgeDocumentDO.java
... ... @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.ai.dal.dataobject.knowledge;
3 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 4 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
5 5 import cn.iocoder.yudao.module.ai.enums.knowledge.AiKnowledgeDocumentStatusEnum;
  6 +import com.baomidou.mybatisplus.annotation.KeySequence;
6 7 import com.baomidou.mybatisplus.annotation.TableId;
7 8 import com.baomidou.mybatisplus.annotation.TableName;
8 9 import lombok.Data;
... ... @@ -13,6 +14,7 @@ import lombok.Data;
13 14 * @author xiaoxin
14 15 */
15 16 @TableName(value = "ai_knowledge_document")
  17 +@KeySequence("ai_knowledge_document_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
16 18 @Data
17 19 public class AiKnowledgeDocumentDO extends BaseDO {
18 20  
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/knowledge/AiKnowledgeSegmentDO.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.ai.dal.dataobject.knowledge;
2 2  
3 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 4 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  5 +import com.baomidou.mybatisplus.annotation.KeySequence;
5 6 import com.baomidou.mybatisplus.annotation.TableId;
6 7 import com.baomidou.mybatisplus.annotation.TableName;
7 8 import lombok.Data;
... ... @@ -12,6 +13,7 @@ import lombok.Data;
12 13 * @author xiaoxin
13 14 */
14 15 @TableName(value = "ai_knowledge_segment")
  16 +@KeySequence("ai_knowledge_segment_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
15 17 @Data
16 18 public class AiKnowledgeSegmentDO extends BaseDO {
17 19  
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/mindmap/AiMindMapDO.java
... ... @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.ai.dal.dataobject.mindmap;
2 2  
3 3 import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum;
4 4 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
5   -import com.baomidou.mybatisplus.annotation.IdType;
  5 +import com.baomidou.mybatisplus.annotation.KeySequence;
6 6 import com.baomidou.mybatisplus.annotation.TableId;
7 7 import com.baomidou.mybatisplus.annotation.TableName;
8 8 import lombok.Data;
... ... @@ -13,6 +13,7 @@ import lombok.Data;
13 13 * @author xiaoxin
14 14 */
15 15 @TableName(value = "ai_mind_map")
  16 +@KeySequence("ai_mind_map_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
16 17 @Data
17 18 public class AiMindMapDO extends BaseDO {
18 19  
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiChatRoleDO.java
... ... @@ -2,7 +2,9 @@ package cn.iocoder.yudao.module.ai.dal.dataobject.model;
2 2  
3 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 4 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
5   -import com.baomidou.mybatisplus.annotation.*;
  5 +import com.baomidou.mybatisplus.annotation.KeySequence;
  6 +import com.baomidou.mybatisplus.annotation.TableId;
  7 +import com.baomidou.mybatisplus.annotation.TableName;
6 8 import lombok.*;
7 9  
8 10 /**
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/music/AiMusicDO.java
... ... @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum;
4 4 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
5 5 import cn.iocoder.yudao.module.ai.enums.music.AiMusicGenerateModeEnum;
6 6 import cn.iocoder.yudao.module.ai.enums.music.AiMusicStatusEnum;
7   -import com.baomidou.mybatisplus.annotation.IdType;
  7 +import com.baomidou.mybatisplus.annotation.KeySequence;
8 8 import com.baomidou.mybatisplus.annotation.TableField;
9 9 import com.baomidou.mybatisplus.annotation.TableId;
10 10 import com.baomidou.mybatisplus.annotation.TableName;
... ... @@ -19,6 +19,7 @@ import java.util.List;
19 19 * @author xiaoxin
20 20 */
21 21 @TableName(value = "ai_music", autoResultMap = true)
  22 +@KeySequence("ai_music_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
22 23 @Data
23 24 public class AiMusicDO extends BaseDO {
24 25  
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/write/AiWriteDO.java
... ... @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.ai.dal.dataobject.write;
3 3 import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum;
4 4 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
5 5 import cn.iocoder.yudao.module.ai.enums.write.AiWriteTypeEnum;
6   -import com.baomidou.mybatisplus.annotation.IdType;
  6 +import com.baomidou.mybatisplus.annotation.KeySequence;
7 7 import com.baomidou.mybatisplus.annotation.TableId;
8 8 import com.baomidou.mybatisplus.annotation.TableName;
9 9 import lombok.Data;
... ... @@ -14,6 +14,7 @@ import lombok.Data;
14 14 * @author xiaoxin
15 15 */
16 16 @TableName("ai_write")
  17 +@KeySequence("ai_write_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
17 18 @Data
18 19 public class AiWriteDO extends BaseDO {
19 20  
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskPageReqVO.java
... ... @@ -4,8 +4,6 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam;
4 4 import cn.iocoder.yudao.framework.common.util.date.DateUtils;
5 5 import io.swagger.v3.oas.annotations.media.Schema;
6 6 import lombok.Data;
7   -import lombok.EqualsAndHashCode;
8   -import lombok.ToString;
9 7 import org.springframework.format.annotation.DateTimeFormat;
10 8  
11 9 import java.time.LocalDateTime;
... ... @@ -17,6 +15,9 @@ public class BpmTaskPageReqVO extends PageParam {
17 15 @Schema(description = "流程任务名", example = "芋道")
18 16 private String name;
19 17  
  18 + @Schema(description = "流程分类", example = "1")
  19 + private String category;
  20 +
20 21 @Schema(description = "创建时间")
21 22 @DateTimeFormat(pattern = DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
22 23 private LocalDateTime[] createTime;
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java
... ... @@ -124,12 +124,18 @@ public interface BpmTaskConvert {
124 124 }
125 125  
126 126 default BpmTaskRespVO buildTodoTask(Task todoTask, List<Task> childrenTasks,
127   - Map<Integer, BpmTaskRespVO.OperationButtonSetting> buttonsSetting) {
128   - return BeanUtils.toBean(todoTask, BpmTaskRespVO.class)
  127 + Map<Integer, BpmTaskRespVO.OperationButtonSetting> buttonsSetting,
  128 + BpmFormDO form) {
  129 + BpmTaskRespVO bpmTaskRespVO = BeanUtils.toBean(todoTask, BpmTaskRespVO.class)
129 130 .setStatus(FlowableUtils.getTaskStatus(todoTask)).setReason(FlowableUtils.getTaskReason(todoTask))
130 131 .setButtonsSetting(buttonsSetting)
131 132 .setChildren(convertList(childrenTasks, childTask -> BeanUtils.toBean(childTask, BpmTaskRespVO.class)
132 133 .setStatus(FlowableUtils.getTaskStatus(childTask))));
  134 + if (form != null) {
  135 + bpmTaskRespVO.setFormId(form.getId()).setFormName(form.getName())
  136 + .setFormConf(form.getConf()).setFormFields(form.getFields());
  137 + }
  138 + return bpmTaskRespVO;
133 139 }
134 140  
135 141 default BpmMessageSendWhenTaskCreatedReqDTO convert(ProcessInstance processInstance, AdminUserRespDTO startUser,
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmCategoryDO.java
... ... @@ -4,7 +4,10 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
4 4 import com.baomidou.mybatisplus.annotation.KeySequence;
5 5 import com.baomidou.mybatisplus.annotation.TableId;
6 6 import com.baomidou.mybatisplus.annotation.TableName;
7   -import lombok.*;
  7 +import lombok.AllArgsConstructor;
  8 +import lombok.Builder;
  9 +import lombok.Data;
  10 +import lombok.NoArgsConstructor;
8 11  
9 12 /**
10 13 * BPM 流程分类 DO
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmFormDO.java
1 1 package cn.iocoder.yudao.module.bpm.dal.dataobject.definition;
2 2  
3 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import com.baomidou.mybatisplus.annotation.KeySequence;
4 5 import com.baomidou.mybatisplus.annotation.TableField;
5 6 import com.baomidou.mybatisplus.annotation.TableId;
6 7 import com.baomidou.mybatisplus.annotation.TableName;
7 8 import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
8   -import lombok.*;
  9 +import lombok.AllArgsConstructor;
  10 +import lombok.Builder;
  11 +import lombok.Data;
  12 +import lombok.NoArgsConstructor;
9 13  
10 14 import java.util.List;
11 15  
... ... @@ -16,6 +20,7 @@ import java.util.List;
16 20 * @author 芋道源码
17 21 */
18 22 @TableName(value = "bpm_form", autoResultMap = true)
  23 +@KeySequence("bpm_form_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
19 24 @Data
20 25 @Builder
21 26 @NoArgsConstructor
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessDefinitionInfoDO.java
... ... @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.mybatis.core.type.StringListTypeHandler;
6 6 import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum;
7 7 import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelTypeEnum;
8 8 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
  9 +import com.baomidou.mybatisplus.annotation.KeySequence;
9 10 import com.baomidou.mybatisplus.annotation.TableField;
10 11 import com.baomidou.mybatisplus.annotation.TableId;
11 12 import com.baomidou.mybatisplus.annotation.TableName;
... ... @@ -26,6 +27,7 @@ import java.util.List;
26 27 * @author 芋道源码
27 28 */
28 29 @TableName(value = "bpm_process_definition_info", autoResultMap = true)
  30 +@KeySequence("bpm_process_definition_info_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
29 31 @Data
30 32 @Builder
31 33 @NoArgsConstructor
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessExpressionDO.java
1 1 package cn.iocoder.yudao.module.bpm.dal.dataobject.definition;
2 2  
3   -import lombok.*;
4   -import java.util.*;
5   -import java.time.LocalDateTime;
6   -import java.time.LocalDateTime;
7   -import com.baomidou.mybatisplus.annotation.*;
8 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import com.baomidou.mybatisplus.annotation.KeySequence;
  5 +import com.baomidou.mybatisplus.annotation.TableId;
  6 +import com.baomidou.mybatisplus.annotation.TableName;
  7 +import lombok.*;
9 8  
10 9 /**
11 10 * BPM 流程表达式 DO
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessListenerDO.java
1 1 package cn.iocoder.yudao.module.bpm.dal.dataobject.definition;
2 2  
3 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import com.baomidou.mybatisplus.annotation.KeySequence;
4 5 import com.baomidou.mybatisplus.annotation.TableId;
5 6 import com.baomidou.mybatisplus.annotation.TableName;
6 7 import lombok.AllArgsConstructor;
... ... @@ -16,6 +17,7 @@ import lombok.NoArgsConstructor;
16 17 * @author 芋道源码
17 18 */
18 19 @TableName(value = "bpm_process_listener")
  20 +@KeySequence("bpm_process_listener_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
19 21 @Data
20 22 @Builder
21 23 @NoArgsConstructor
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmUserGroupDO.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.bpm.dal.dataobject.definition;
2 2  
3 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 4 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  5 +import com.baomidou.mybatisplus.annotation.KeySequence;
5 6 import com.baomidou.mybatisplus.annotation.TableField;
6 7 import com.baomidou.mybatisplus.annotation.TableId;
7 8 import com.baomidou.mybatisplus.annotation.TableName;
... ... @@ -19,6 +20,7 @@ import java.util.Set;
19 20 * @author 芋道源码
20 21 */
21 22 @TableName(value = "bpm_user_group", autoResultMap = true)
  23 +@KeySequence("bpm_user_group_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
22 24 @Data
23 25 @Builder
24 26 @NoArgsConstructor
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOALeaveDO.java
... ... @@ -2,9 +2,13 @@ package cn.iocoder.yudao.module.bpm.dal.dataobject.oa;
2 2  
3 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
4 4 import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum;
  5 +import com.baomidou.mybatisplus.annotation.KeySequence;
5 6 import com.baomidou.mybatisplus.annotation.TableId;
6 7 import com.baomidou.mybatisplus.annotation.TableName;
7   -import lombok.*;
  8 +import lombok.AllArgsConstructor;
  9 +import lombok.Builder;
  10 +import lombok.Data;
  11 +import lombok.NoArgsConstructor;
8 12  
9 13 import java.time.LocalDateTime;
10 14  
... ... @@ -17,6 +21,7 @@ import java.time.LocalDateTime;
17 21 * @author 芋道源码
18 22 */
19 23 @TableName("bpm_oa_leave")
  24 +@KeySequence("bpm_oa_leave_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
20 25 @Data
21 26 @Builder
22 27 @NoArgsConstructor
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmProcessInstanceCopyDO.java
1 1 package cn.iocoder.yudao.module.bpm.dal.dataobject.task;
2 2  
3 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import com.baomidou.mybatisplus.annotation.KeySequence;
4 5 import com.baomidou.mybatisplus.annotation.TableId;
5 6 import com.baomidou.mybatisplus.annotation.TableName;
6   -import lombok.*;
7 7 import org.flowable.bpmn.model.FlowNode;
8 8 import org.flowable.task.api.history.HistoricTaskInstance;
  9 +import lombok.AllArgsConstructor;
  10 +import lombok.Builder;
  11 +import lombok.Data;
  12 +import lombok.NoArgsConstructor;
9 13  
10 14 /**
11 15 * 流程抄送 DO
... ... @@ -14,6 +18,7 @@ import org.flowable.task.api.history.HistoricTaskInstance;
14 18 * @since 2024-01-22
15 19 */
16 20 @TableName(value = "bpm_process_instance_copy", autoResultMap = true)
  21 +@KeySequence("bpm_process_instance_copy_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
17 22 @Data
18 23 @Builder
19 24 @NoArgsConstructor
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java
... ... @@ -278,8 +278,8 @@ public class BpmnModelUtils {
278 278 }
279 279 Map<String, String> fieldsPermission = MapUtil.newHashMap();
280 280 extensionElements.forEach(element -> {
281   - String field = element.getAttributeValue(FLOWABLE_EXTENSIONS_NAMESPACE, FORM_FIELD_PERMISSION_ELEMENT_FIELD_ATTRIBUTE);
282   - String permission = element.getAttributeValue(FLOWABLE_EXTENSIONS_NAMESPACE, FORM_FIELD_PERMISSION_ELEMENT_PERMISSION_ATTRIBUTE);
  281 + String field = element.getAttributeValue(null, FORM_FIELD_PERMISSION_ELEMENT_FIELD_ATTRIBUTE);
  282 + String permission = element.getAttributeValue(null, FORM_FIELD_PERMISSION_ELEMENT_PERMISSION_ATTRIBUTE);
283 283 if (StrUtil.isNotEmpty(field) && StrUtil.isNotEmpty(permission)) {
284 284 fieldsPermission.put(field, permission);
285 285 }
... ... @@ -321,9 +321,9 @@ public class BpmnModelUtils {
321 321 }
322 322 Map<Integer, BpmTaskRespVO.OperationButtonSetting> buttonSettings = Maps.newHashMapWithExpectedSize(extensionElements.size());
323 323 extensionElements.forEach(element -> {
324   - String id = element.getAttributeValue(FLOWABLE_EXTENSIONS_NAMESPACE, BUTTON_SETTING_ELEMENT_ID_ATTRIBUTE);
325   - String displayName = element.getAttributeValue(FLOWABLE_EXTENSIONS_NAMESPACE, BUTTON_SETTING_ELEMENT_DISPLAY_NAME_ATTRIBUTE);
326   - String enable = element.getAttributeValue(FLOWABLE_EXTENSIONS_NAMESPACE, BUTTON_SETTING_ELEMENT_ENABLE_ATTRIBUTE);
  324 + String id = element.getAttributeValue(null, BUTTON_SETTING_ELEMENT_ID_ATTRIBUTE);
  325 + String displayName = element.getAttributeValue(null, BUTTON_SETTING_ELEMENT_DISPLAY_NAME_ATTRIBUTE);
  326 + String enable = element.getAttributeValue(null, BUTTON_SETTING_ELEMENT_ENABLE_ATTRIBUTE);
327 327 if (StrUtil.isNotEmpty(id)) {
328 328 BpmTaskRespVO.OperationButtonSetting setting = new BpmTaskRespVO.OperationButtonSetting();
329 329 buttonSettings.put(Integer.valueOf(id), setting.setDisplayName(displayName).setEnable(Boolean.parseBoolean(enable)));
... ... @@ -720,7 +720,7 @@ public class BpmnModelUtils {
720 720 && evalConditionExpress(variables, flow.getConditionExpression()));
721 721 if (matchSequenceFlow == null) {
722 722 matchSequenceFlow = CollUtil.findOne(gateway.getOutgoingFlows(),
723   - flow -> ObjUtil.notEqual(gateway.getDefaultFlow(), flow.getId()));
  723 + flow -> ObjUtil.equal(gateway.getDefaultFlow(), flow.getId()));
724 724 // 特殊:没有默认的情况下,并且只有 1 个条件,则认为它是默认的
725 725 if (matchSequenceFlow == null && gateway.getOutgoingFlows().size() == 1) {
726 726 matchSequenceFlow = gateway.getOutgoingFlows().get(0);
... ... @@ -742,7 +742,7 @@ public class BpmnModelUtils {
742 742 && evalConditionExpress(variables, flow.getConditionExpression()));
743 743 if (CollUtil.isEmpty(matchSequenceFlows)) {
744 744 matchSequenceFlows = CollUtil.filterNew(gateway.getOutgoingFlows(),
745   - flow -> ObjUtil.notEqual(gateway.getDefaultFlow(), flow.getId()));
  745 + flow -> ObjUtil.equal(gateway.getDefaultFlow(), flow.getId()));
746 746 // 特殊:没有默认的情况下,并且只有 1 个条件,则认为它是默认的
747 747 if (CollUtil.isEmpty(matchSequenceFlows) && gateway.getOutgoingFlows().size() == 1) {
748 748 matchSequenceFlows = gateway.getOutgoingFlows();
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java
... ... @@ -65,7 +65,7 @@ public class BpmModelServiceImpl implements BpmModelService {
65 65 public List<Model> getModelList(String name) {
66 66 ModelQuery modelQuery = repositoryService.createModelQuery();
67 67 if (StrUtil.isNotEmpty(name)) {
68   - modelQuery.modelNameLike(name);
  68 + modelQuery.modelNameLike("%" + name + "%");
69 69 }
70 70 return modelQuery.list();
71 71 }
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
1   -package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.ListUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import cn.iocoder.yudao.framework.common.util.object.PageUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmApprovalDetailRespVO.ActivityNodeTask; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; import cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants; import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelTypeEnum; import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum; import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept.BpmTaskCandidateStartUserSelectStrategy; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants; import cn.iocoder.yudao.module.bpm.framework.flowable.core.event.BpmProcessInstanceEventPublisher; import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.SimpleModelUtils; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import jakarta.annotation.Resource; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.constants.BpmnXMLConstants; import org.flowable.bpmn.model.*; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; 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.ProcessInstance; import org.flowable.task.api.history.HistoricTaskInstance; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 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.framework.flowable.core.enums.BpmnModelConstants.START_USER_NODE_ID; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; import static org.flowable.bpmn.constants.BpmnXMLConstants.*; /** * 流程实例 Service 实现类 * <p> * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. <a href="https://blog.csdn.net/bobozai86/article/details/105210414" /> * <p> * HistoricProcessInstance & ProcessInstance 的关系: * 1. <a href=" https://my.oschina.net/843294669/blog/71902" /> * <p> * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private HistoryService historyService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource @Lazy // 避免循环依赖 private BpmTaskService taskService; @Resource private BpmMessageService messageService; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Resource private BpmProcessInstanceEventPublisher processInstanceEventPublisher; @Resource private BpmTaskCandidateInvoker taskCandidateInvoker; // ========== Query 查询相关方法 ========== @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery() .includeProcessVariables() .processInstanceId(id) .singleResult(); } @Override public List<ProcessInstance> getProcessInstances(Set<String> ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).includeProcessVariables().singleResult(); } @Override public List<HistoricProcessInstance> getHistoricProcessInstances(Set<String> ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult<HistoricProcessInstance> getProcessInstancePage(Long userId, BpmProcessInstancePageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery() .includeProcessVariables() .processInstanceTenantId(FlowableUtils.getTenantId()) .orderByProcessInstanceStartTime().desc(); if (userId != null) { // 【我的流程】菜单时,需要传递该字段 processInstanceQuery.startedBy(String.valueOf(userId)); } else if (pageReqVO.getStartUserId() != null) { // 【管理流程】菜单时,才会传递该字段 processInstanceQuery.startedBy(String.valueOf(pageReqVO.getStartUserId())); } if (StrUtil.isNotEmpty(pageReqVO.getName())) { processInstanceQuery.processInstanceNameLike("%" + pageReqVO.getName() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getProcessDefinitionKey())) { processInstanceQuery.processDefinitionKey(pageReqVO.getProcessDefinitionKey()); } if (StrUtil.isNotEmpty(pageReqVO.getCategory())) { processInstanceQuery.processDefinitionCategory(pageReqVO.getCategory()); } if (pageReqVO.getStatus() != null) { processInstanceQuery.variableValueEquals(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS, pageReqVO.getStatus()); } if (ArrayUtil.isNotEmpty(pageReqVO.getCreateTime())) { processInstanceQuery.startedAfter(DateUtils.of(pageReqVO.getCreateTime()[0])); processInstanceQuery.startedBefore(DateUtils.of(pageReqVO.getCreateTime()[1])); } // 查询数量 long processInstanceCount = processInstanceQuery.count(); if (processInstanceCount == 0) { return PageResult.empty(processInstanceCount); } // 查询列表 List<HistoricProcessInstance> processInstanceList = processInstanceQuery.listPage(PageUtils.getStart(pageReqVO), pageReqVO.getPageSize()); return new PageResult<>(processInstanceList, processInstanceCount); } private Map<String, String> getFormFieldsPermission(BpmnModel bpmnModel, String activityId, String taskId) { // 1. 获取流程活动编号。流程活动 Id 为空事,从流程任务中获取流程活动 Id if (StrUtil.isEmpty(activityId) && StrUtil.isNotEmpty(taskId)) { activityId = Optional.ofNullable(taskService.getHistoricTask(taskId)) .map(HistoricTaskInstance::getTaskDefinitionKey).orElse(null); } if (StrUtil.isEmpty(activityId)) { return null; } // 2. 从 BpmnModel 中解析表单字段权限 return BpmnModelUtils.parseFormFieldsPermission(bpmnModel, activityId); } @Override public BpmApprovalDetailRespVO getApprovalDetail(Long loginUserId, BpmApprovalDetailReqVO reqVO) { // 1.1 从 reqVO 中,读取公共变量 Long startUserId = loginUserId; // 流程发起人 HistoricProcessInstance historicProcessInstance = null; // 流程实例 Integer processInstanceStatus = BpmProcessInstanceStatusEnum.NOT_START.getStatus(); // 流程状态 Map<String, Object> processVariables = reqVO.getProcessVariables(); // 流程变量 // 1.2 如果是流程已发起的场景,则使用流程实例的数据 if (reqVO.getProcessInstanceId() != null) { historicProcessInstance = getHistoricProcessInstance(reqVO.getProcessInstanceId()); if (historicProcessInstance == null) { throw exception(ErrorCodeConstants.PROCESS_INSTANCE_NOT_EXISTS); } startUserId = Long.valueOf(historicProcessInstance.getStartUserId()); processInstanceStatus = FlowableUtils.getProcessInstanceStatus(historicProcessInstance); processVariables = historicProcessInstance.getProcessVariables(); } // 1.3 读取其它相关数据 ProcessDefinition processDefinition = processDefinitionService.getProcessDefinition( historicProcessInstance != null ? historicProcessInstance.getProcessDefinitionId() : reqVO.getProcessDefinitionId()); BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService.getProcessDefinitionInfo(processDefinition.getId()); BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(processDefinition.getId()); // 2.1 已结束 + 进行中的活动节点 List<ActivityNode> endActivityNodes = null; // 已结束的审批信息 List<ActivityNode> runActivityNodes = null; // 进行中的审批信息 List<HistoricActivityInstance> activities = null; // 流程实例列表 if (reqVO.getProcessInstanceId() != null) { activities = taskService.getActivityListByProcessInstanceId(reqVO.getProcessInstanceId()); List<HistoricTaskInstance> tasks = taskService.getTaskListByProcessInstanceId(reqVO.getProcessInstanceId(), true); endActivityNodes = getEndActivityNodeList(startUserId, bpmnModel, processDefinitionInfo, historicProcessInstance, processInstanceStatus, activities, tasks); runActivityNodes = getRunApproveNodeList(startUserId, bpmnModel, processDefinition, processVariables, activities, tasks); } // 2.2 流程已经结束,直接 return,无需预测 if (BpmProcessInstanceStatusEnum.isProcessEndStatus(processInstanceStatus)) { return buildApprovalDetail(reqVO, bpmnModel, processDefinition, processDefinitionInfo, historicProcessInstance, processInstanceStatus, endActivityNodes, runActivityNodes, null, null); } // 3.1 计算当前登录用户的待办任务 // TODO @jason:有一个极端情况,如果一个用户有 2 个 task A 和 B,A 已经通过,B 需要审核。这个时,通过 A 进来,todo 拿到 B,会不会表单权限不一致哈。 BpmTaskRespVO todoTask = taskService.getFirstTodoTask(loginUserId, reqVO.getProcessInstanceId()); // 3.2 预测未运行节点的审批信息 List<ActivityNode> simulateActivityNodes = getSimulateApproveNodeList(startUserId, bpmnModel, processDefinitionInfo, processVariables, activities); // 4. 拼接最终数据 return buildApprovalDetail(reqVO, bpmnModel, processDefinition, processDefinitionInfo, historicProcessInstance, processInstanceStatus, endActivityNodes, runActivityNodes, simulateActivityNodes, todoTask); } /** * 拼接审批详情的最终数据 * <p> * 主要是,拼接审批人的用户信息、部门信息 */ private BpmApprovalDetailRespVO buildApprovalDetail(BpmApprovalDetailReqVO reqVO, BpmnModel bpmnModel, ProcessDefinition processDefinition, BpmProcessDefinitionInfoDO processDefinitionInfo, HistoricProcessInstance processInstance, Integer processInstanceStatus, List<ActivityNode> endApprovalNodeInfos, List<ActivityNode> runningApprovalNodeInfos, List<ActivityNode> simulateApprovalNodeInfos, BpmTaskRespVO todoTask) { // 1. 获取所有需要读取用户信息的 userIds List<ActivityNode> approveNodes = newArrayList(asList(endApprovalNodeInfos, runningApprovalNodeInfos, simulateApprovalNodeInfos)); Set<Long> userIds = BpmProcessInstanceConvert.INSTANCE.parseUserIds(processInstance, approveNodes, todoTask); Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds); Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); // 2. 表单权限 Map<String, String> formFieldsPermission = getFormFieldsPermission(bpmnModel, reqVO.getActivityId(), reqVO.getTaskId()); // 3. 拼接数据 return BpmProcessInstanceConvert.INSTANCE.buildApprovalDetail(bpmnModel, processDefinition, processDefinitionInfo, processInstance, processInstanceStatus, approveNodes, todoTask, formFieldsPermission, userMap, deptMap); } /** * 获得【已结束】的活动节点们 */ private List<ActivityNode> getEndActivityNodeList(Long startUserId, BpmnModel bpmnModel, BpmProcessDefinitionInfoDO processDefinitionInfo, HistoricProcessInstance historicProcessInstance, Integer processInstanceStatus, List<HistoricActivityInstance> activities, List<HistoricTaskInstance> tasks) { // 遍历 tasks 列表,只处理已结束的 UserTask // 为什么不通过 activities 呢?因为,加签场景下,它只存在于 tasks,没有 activities,导致如果遍历 activities 的话,它无法成为一个节点 List<HistoricTaskInstance> endTasks = filterList(tasks, task -> task.getEndTime() != null); List<ActivityNode> approvalNodes = convertList(endTasks, task -> { FlowElement flowNode = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey()); ActivityNode activityNode = new ActivityNode().setId(task.getTaskDefinitionKey()).setName(task.getName()) .setNodeType(START_USER_NODE_ID.equals(task.getTaskDefinitionKey()) ? BpmSimpleModelNodeType.START_USER_NODE.getType() : BpmSimpleModelNodeType.APPROVE_NODE.getType()) .setStatus(FlowableUtils.getTaskStatus(task)) .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(flowNode)) .setStartTime(DateUtils.of(task.getCreateTime())).setEndTime(DateUtils.of(task.getEndTime())) .setTasks(singletonList(BpmProcessInstanceConvert.INSTANCE.buildApprovalTaskInfo(task))); // 如果是取消状态,则跳过 if (BpmTaskStatusEnum.isCancelStatus(activityNode.getStatus())) { return null; } return activityNode; }); // 遍历 activities,只处理已结束的 StartEvent、EndEvent List<HistoricActivityInstance> endActivities = filterList(activities, activity -> activity.getEndTime() != null && (StrUtil.equalsAny(activity.getActivityType(), ELEMENT_EVENT_START, ELEMENT_EVENT_END))); endActivities.forEach(activity -> { // StartEvent:只处理 BPMN 的场景。因为,SIMPLE 情况下,已经有 START_USER_NODE 节点 if (ELEMENT_EVENT_START.equals(activity.getActivityType()) && BpmModelTypeEnum.BPMN.getType().equals(processDefinitionInfo.getModelType())) { ActivityNodeTask startTask = new ActivityNodeTask().setId(BpmnModelConstants.START_USER_NODE_ID) .setAssignee(startUserId).setStatus(BpmTaskStatusEnum.APPROVE.getStatus()); ActivityNode startNode = new ActivityNode().setId(startTask.getId()) .setName(BpmSimpleModelNodeType.START_USER_NODE.getName()) .setNodeType(BpmSimpleModelNodeType.START_USER_NODE.getType()) .setStatus(startTask.getStatus()).setTasks(ListUtil.of(startTask)) .setStartTime(DateUtils.of(activity.getStartTime())).setEndTime(DateUtils.of(activity.getEndTime())); approvalNodes.add(0, startNode); return; } // EndEvent if (ELEMENT_EVENT_END.equals(activity.getActivityType())) { if (BpmProcessInstanceStatusEnum.isRejectStatus(processInstanceStatus)) { // 拒绝情况下,不需要展示 EndEvent 结束节点。原因是:前端已经展示 x 效果,无需重复展示 return; } ActivityNode endNode = new ActivityNode().setId(activity.getId()) .setName(BpmSimpleModelNodeType.END_NODE.getName()) .setNodeType(BpmSimpleModelNodeType.END_NODE.getType()).setStatus(processInstanceStatus) .setStartTime(DateUtils.of(activity.getStartTime())).setEndTime(DateUtils.of(activity.getEndTime())); String reason = FlowableUtils.getProcessInstanceReason(historicProcessInstance); if (StrUtil.isNotEmpty(reason)) { endNode.setTasks(singletonList(new ActivityNodeTask().setId(endNode.getId()) .setStatus(endNode.getStatus()).setReason(reason))); } approvalNodes.add(endNode); } }); return approvalNodes; } /** * 获得【进行中】的活动节点们 */ private List<ActivityNode> getRunApproveNodeList(Long startUserId, BpmnModel bpmnModel, ProcessDefinition processDefinition, Map<String, Object> processVariables, List<HistoricActivityInstance> activities, List<HistoricTaskInstance> tasks) { // 构建运行中的任务,基于 activityId 分组 List<HistoricActivityInstance> runActivities = filterList(activities, activity -> activity.getEndTime() == null && (StrUtil.equalsAny(activity.getActivityType(), ELEMENT_TASK_USER))); Map<String, List<HistoricActivityInstance>> runningTaskMap = convertMultiMap(runActivities, HistoricActivityInstance::getActivityId); // 按照 activityId 分组,构建 ApprovalNodeInfo 节点 Map<String, HistoricTaskInstance> taskMap = convertMap(tasks, HistoricTaskInstance::getId); return convertList(runningTaskMap.entrySet(), entry -> { String activityId = entry.getKey(); List<HistoricActivityInstance> taskActivities = entry.getValue(); // 构建活动节点 FlowElement flowNode = BpmnModelUtils.getFlowElementById(bpmnModel, activityId); HistoricActivityInstance firstActivity = CollUtil.getFirst(taskActivities); // 取第一个任务,会签/或签的任务,开始时间相同 ActivityNode activityNode = new ActivityNode().setId(firstActivity.getActivityId()).setName(firstActivity.getActivityName()) .setNodeType(BpmSimpleModelNodeType.APPROVE_NODE.getType()).setStatus(BpmTaskStatusEnum.RUNNING.getStatus()) .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(flowNode)) .setStartTime(DateUtils.of(CollUtil.getFirst(taskActivities).getStartTime())) .setTasks(new ArrayList<>()); // 处理每个任务的 tasks 属性 for (HistoricActivityInstance activity : taskActivities) { HistoricTaskInstance task = taskMap.get(activity.getTaskId()); activityNode.getTasks().add(BpmProcessInstanceConvert.INSTANCE.buildApprovalTaskInfo(task)); // 加签子任务,需要过滤掉已经完成的加签子任务 List<HistoricTaskInstance> childrenTasks = filterList( taskService.getAllChildrenTaskListByParentTaskId(activity.getTaskId(), tasks), childTask -> childTask.getEndTime() == null); if (CollUtil.isNotEmpty(childrenTasks)) { activityNode.getTasks().addAll(convertList(childrenTasks, BpmProcessInstanceConvert.INSTANCE::buildApprovalTaskInfo)); } } // 处理每个任务的 candidateUsers 属性:如果是依次审批,需要预测它的后续审批人。因为 Task 是审批完一个,创建一个新的 Task if (BpmnModelUtils.isSequentialUserTask(flowNode)) { List<Long> candidateUserIds = getTaskCandidateUserList(bpmnModel, flowNode.getId(), startUserId, processDefinition.getId(), processVariables); // 截取当前审批人位置后面的候选人,不包含当前审批人 ActivityNodeTask approvalTaskInfo = CollUtil.getFirst(activityNode.getTasks()); Assert.notNull(approvalTaskInfo, "任务不能为空"); int index = CollUtil.indexOf(candidateUserIds, userId -> ObjectUtils.equalsAny(userId, approvalTaskInfo.getOwner(), approvalTaskInfo.getAssignee())); // 委派或者向前加签情况,需要先比较 owner activityNode.setCandidateUserIds(CollUtil.sub(candidateUserIds, index + 1, candidateUserIds.size())); } return activityNode; }); } /** * 获得【预测(未来)】的活动节点们 */ private List<ActivityNode> getSimulateApproveNodeList(Long startUserId, BpmnModel bpmnModel, BpmProcessDefinitionInfoDO processDefinitionInfo, Map<String, Object> processVariables, List<HistoricActivityInstance> activities) { // TODO @芋艿:【可优化】在驳回场景下,未来的预测准确性不高。原因是,驳回后,HistoricActivityInstance 包括了历史的操作,不是只有 startEvent 到当前节点的记录 Set<String> runActivityIds = convertSet(activities, HistoricActivityInstance::getActivityId); // 情况一:BPMN 设计器 if (Objects.equals(BpmModelTypeEnum.BPMN.getType(), processDefinitionInfo.getModelType())) { List<FlowElement> flowElements = BpmnModelUtils.simulateProcess(bpmnModel, processVariables); return convertList(flowElements, flowElement -> buildNotRunApproveNodeForBpmn(startUserId, bpmnModel, processDefinitionInfo, processVariables, flowElement, runActivityIds)); } // 情况二:SIMPLE 设计器 if (Objects.equals(BpmModelTypeEnum.SIMPLE.getType(), processDefinitionInfo.getModelType())) { BpmSimpleModelNodeVO simpleModel = JsonUtils.parseObject(processDefinitionInfo.getSimpleModel(), BpmSimpleModelNodeVO.class); List<BpmSimpleModelNodeVO> simpleNodes = SimpleModelUtils.simulateProcess(simpleModel, processVariables); return convertList(simpleNodes, simpleNode -> buildNotRunApproveNodeForSimple(startUserId, bpmnModel, processDefinitionInfo, processVariables, simpleNode, runActivityIds)); } throw new IllegalArgumentException("未知设计器类型:" + processDefinitionInfo.getModelType()); } private ActivityNode buildNotRunApproveNodeForSimple(Long startUserId, BpmnModel bpmnModel, BpmProcessDefinitionInfoDO processDefinitionInfo, Map<String, Object> processVariables, BpmSimpleModelNodeVO node, Set<String> runActivityIds) { // TODO @芋艿:【可优化】在驳回场景下,未来的预测准确性不高。原因是,驳回后,HistoricActivityInstance 包括了历史的操作,不是只有 startEvent 到当前节点的记录 if (runActivityIds.contains(node.getId())) { return null; } ActivityNode activityNode = new ActivityNode().setId(node.getId()).setName(node.getName()) .setNodeType(node.getType()).setCandidateStrategy(node.getCandidateStrategy()) .setStatus(BpmTaskStatusEnum.NOT_START.getStatus()); // 1. 开始节点/审批节点 if (ObjectUtils.equalsAny(node.getType(), BpmSimpleModelNodeType.START_USER_NODE.getType(), BpmSimpleModelNodeType.APPROVE_NODE.getType())) { List<Long> candidateUserIds = getTaskCandidateUserList(bpmnModel, node.getId(), startUserId, processDefinitionInfo.getProcessDefinitionId(), processVariables); activityNode.setCandidateUserIds(candidateUserIds); return activityNode; } // 2. 结束节点 if (BpmSimpleModelNodeType.END_NODE.getType().equals(node.getType())) { return activityNode; } // 3. 抄送节点 if (CollUtil.isEmpty(runActivityIds) && // 流程发起时:需要展示抄送节点,用于选择抄送人 BpmSimpleModelNodeType.COPY_NODE.getType().equals(node.getType())) { return activityNode; } return null; } private ActivityNode buildNotRunApproveNodeForBpmn(Long startUserId, BpmnModel bpmnModel, BpmProcessDefinitionInfoDO processDefinitionInfo, Map<String, Object> processVariables, FlowElement node, Set<String> runActivityIds) { if (runActivityIds.contains(node.getId())) { return null; } ActivityNode activityNode = new ActivityNode().setId(node.getId()).setStatus(BpmTaskStatusEnum.NOT_START.getStatus()); // 1. 开始节点 if (node instanceof StartEvent) { return activityNode.setName(BpmSimpleModelNodeType.START_USER_NODE.getName()) .setNodeType(BpmSimpleModelNodeType.START_USER_NODE.getType()); } // 2. 审批节点 if (node instanceof UserTask) { List<Long> candidateUserIds = getTaskCandidateUserList(bpmnModel, node.getId(), startUserId, processDefinitionInfo.getProcessDefinitionId(), processVariables); return activityNode.setName(node.getName()).setNodeType(BpmSimpleModelNodeType.APPROVE_NODE.getType()) .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(node)) .setCandidateUserIds(candidateUserIds); } // 3. 结束节点 if (node instanceof EndEvent) { return activityNode.setName(BpmSimpleModelNodeType.END_NODE.getName()) .setNodeType(BpmSimpleModelNodeType.END_NODE.getType()); } return null; } private List<Long> getTaskCandidateUserList(BpmnModel bpmnModel, String activityId, Long startUserId, String processDefinitionId, Map<String, Object> processVariables) { Set<Long> userIds = taskCandidateInvoker.calculateUsersByActivity(bpmnModel, activityId, startUserId, processDefinitionId, processVariables); return new ArrayList<>(userIds); } @Override public BpmProcessInstanceBpmnModelViewRespVO getProcessInstanceBpmnModelView(String id) { // 1.1 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } // 1.2 获得流程定义 BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(processInstance.getProcessDefinitionId()); if (bpmnModel == null) { return null; } BpmSimpleModelNodeVO simpleModel = null; BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService.getProcessDefinitionInfo( processInstance.getProcessDefinitionId()); if (processDefinitionInfo != null && BpmModelTypeEnum.SIMPLE.getType().equals(processDefinitionInfo.getModelType())) { simpleModel = JsonUtils.parseObject(processDefinitionInfo.getSimpleModel(), BpmSimpleModelNodeVO.class); } // 1.3 获得流程实例对应的活动实例列表 + 任务列表 List<HistoricActivityInstance> activities = taskService.getActivityListByProcessInstanceId(id); List<HistoricTaskInstance> tasks = taskService.getTaskListByProcessInstanceId(id, true); // 2.1 拼接进度信息 Set<String> unfinishedTaskActivityIds = convertSet(activities, HistoricActivityInstance::getActivityId, activityInstance -> activityInstance.getEndTime() == null); Set<String> finishedTaskActivityIds = convertSet(activities, HistoricActivityInstance::getActivityId, activityInstance -> activityInstance.getEndTime() != null && ObjectUtil.notEqual(activityInstance.getActivityType(), BpmnXMLConstants.ELEMENT_SEQUENCE_FLOW)); Set<String> finishedSequenceFlowActivityIds = convertSet(activities, HistoricActivityInstance::getActivityId, activityInstance -> activityInstance.getEndTime() != null && ObjectUtil.equals(activityInstance.getActivityType(), BpmnXMLConstants.ELEMENT_SEQUENCE_FLOW)); // 特殊:会签情况下,会有部分已完成(审批)、部分未完成(待审批),此时需要 finishedTaskActivityIds 移除掉 unfinishedTaskActivityIds.removeAll(finishedTaskActivityIds); // 特殊:如果流程实例被拒绝,则需要计算是哪个活动节点。 // 注意,只取最后一个。因为会存在多次拒绝的情况,拒绝驳回到指定节点 Set<String> rejectTaskActivityIds = CollUtil.newHashSet(); if (BpmProcessInstanceStatusEnum.isRejectStatus(FlowableUtils.getProcessInstanceStatus(processInstance))) { tasks.stream() .filter(task -> BpmTaskStatusEnum.isRejectStatus(FlowableUtils.getTaskStatus(task))) .max(Comparator.comparing(HistoricTaskInstance::getEndTime)) .ifPresent(reject -> rejectTaskActivityIds.add(reject.getTaskDefinitionKey())); finishedTaskActivityIds.removeAll(rejectTaskActivityIds); } // 2.2 拼接基础信息 Set<Long> userIds = BpmProcessInstanceConvert.INSTANCE.parseUserIds02(processInstance, tasks); Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds); Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); return BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceBpmnModelView(processInstance, tasks, bpmnModel, simpleModel, unfinishedTaskActivityIds, finishedTaskActivityIds, finishedSequenceFlowActivityIds, rejectTaskActivityIds, userMap, deptMap); } // ========== Update 写入相关方法 ========== @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null, createReqVO.getStartUserSelectAssignees()); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(), createReqDTO.getStartUserSelectAssignees()); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map<String, Object> variables, String businessKey, Map<String, List<Long>> startUserSelectAssignees) { // 1.1 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService.getProcessDefinitionInfo(definition.getId()); if (processDefinitionInfo == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } // 1.2 校验是否能够发起 if (!processDefinitionService.canUserStartProcessDefinition(processDefinitionInfo, userId)) { throw exception(PROCESS_INSTANCE_START_USER_CAN_START); } // 1.3 校验发起人自选审批人 validateStartUserSelectAssignees(definition, startUserSelectAssignees); // 2. 创建流程实例 if (variables == null) { variables = new HashMap<>(); } FlowableUtils.filterProcessInstanceFormVariable(variables); // 过滤一下,避免 ProcessInstance 系统级的变量被占用 variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_ID, userId); // 设置流程变量,发起人 ID variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS, // 流程实例状态:审批中 BpmProcessInstanceStatusEnum.RUNNING.getStatus()); if (CollUtil.isNotEmpty(startUserSelectAssignees)) { variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES, startUserSelectAssignees); } ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); return instance.getId(); } private void validateStartUserSelectAssignees(ProcessDefinition definition, Map<String, List<Long>> startUserSelectAssignees) { // 1. 获得发起人自选审批人的 UserTask/ServiceTask 列表 BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(definition.getId()); List<Task> tasks = BpmTaskCandidateStartUserSelectStrategy.getStartUserSelectTaskList(bpmnModel); if (CollUtil.isEmpty(tasks)) { return; } // 2. 校验发起人自选审批人的审批人和抄送人是否都配置了 tasks.forEach(task -> { List<Long> assignees = startUserSelectAssignees != null ? startUserSelectAssignees.get(task.getId()) : null; if (CollUtil.isEmpty(assignees)) { throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_CONFIG, task.getName()); } Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(assignees); assignees.forEach(assignee -> { if (userMap.get(assignee) == null) { throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_EXISTS, task.getName(), assignee); } }); }); } @Override public void cancelProcessInstanceByStartUser(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 1.1 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 1.2 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 2. 取消流程 updateProcessInstanceCancel(cancelReqVO.getId(), BpmReasonEnum.CANCEL_PROCESS_INSTANCE_BY_START_USER.format(cancelReqVO.getReason())); } @Override public void cancelProcessInstanceByAdmin(Long userId, BpmProcessInstanceCancelReqVO cancelReqVO) { // 1.1 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 2. 取消流程 AdminUserRespDTO user = adminUserApi.getUser(userId); updateProcessInstanceCancel(cancelReqVO.getId(), BpmReasonEnum.CANCEL_PROCESS_INSTANCE_BY_ADMIN.format(user.getNickname(), cancelReqVO.getReason())); } private void updateProcessInstanceCancel(String id, String reason) { // 1. 更新流程实例 status runtimeService.setVariable(id, BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.CANCEL.getStatus()); runtimeService.setVariable(id, BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_REASON, reason); // 2. 结束流程 taskService.moveTaskToEnd(id); } @Override public void updateProcessInstanceReject(ProcessInstance processInstance, String reason) { runtimeService.setVariable(processInstance.getProcessInstanceId(), BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.REJECT.getStatus()); runtimeService.setVariable(processInstance.getProcessInstanceId(), BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_REASON, BpmReasonEnum.REJECT_TASK.format(reason)); } // ========== Event 事件相关方法 ========== @Override public void processProcessInstanceCompleted(ProcessInstance instance) { // 注意:需要基于 instance 设置租户编号,避免 Flowable 内部异步时,丢失租户编号 FlowableUtils.execute(instance.getTenantId(), () -> { // 1.1 获取当前状态 Integer status = (Integer) instance.getProcessVariables().get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS); String reason = (String) instance.getProcessVariables().get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_REASON); // 1.2 当流程状态还是审批状态中,说明审批通过了,则变更下它的状态 // 为什么这么处理?因为流程完成,并且完成了,说明审批通过了 if (Objects.equals(status, BpmProcessInstanceStatusEnum.RUNNING.getStatus())) { status = BpmProcessInstanceStatusEnum.APPROVE.getStatus(); runtimeService.setVariable(instance.getId(), BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS, status); } // 2. 发送对应的消息通知 if (Objects.equals(status, BpmProcessInstanceStatusEnum.APPROVE.getStatus())) { messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceApproveMessage(instance)); } else if (Objects.equals(status, BpmProcessInstanceStatusEnum.REJECT.getStatus())) { messageService.sendMessageWhenProcessInstanceReject( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceRejectMessage(instance, reason)); } // 3. 发送流程实例的状态事件 processInstanceEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, instance, status)); }); } }
2 1 \ No newline at end of file
  2 +package cn.iocoder.yudao.module.bpm.service.task;
  3 +
  4 +import cn.hutool.core.collection.CollUtil;
  5 +import cn.hutool.core.collection.ListUtil;
  6 +import cn.hutool.core.lang.Assert;
  7 +import cn.hutool.core.util.ArrayUtil;
  8 +import cn.hutool.core.util.ObjectUtil;
  9 +import cn.hutool.core.util.StrUtil;
  10 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  11 +import cn.iocoder.yudao.framework.common.util.date.DateUtils;
  12 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
  13 +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
  14 +import cn.iocoder.yudao.framework.common.util.object.PageUtils;
  15 +import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
  16 +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
  17 +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*;
  18 +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmApprovalDetailRespVO.ActivityNodeTask;
  19 +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO;
  20 +import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert;
  21 +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO;
  22 +import cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants;
  23 +import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelTypeEnum;
  24 +import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType;
  25 +import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum;
  26 +import cn.iocoder.yudao.module.bpm.enums.task.BpmReasonEnum;
  27 +import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum;
  28 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker;
  29 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept.BpmTaskCandidateStartUserSelectStrategy;
  30 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
  31 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants;
  32 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.event.BpmProcessInstanceEventPublisher;
  33 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
  34 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
  35 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.SimpleModelUtils;
  36 +import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService;
  37 +import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService;
  38 +import cn.iocoder.yudao.module.system.api.dept.DeptApi;
  39 +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
  40 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
  41 +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
  42 +import jakarta.annotation.Resource;
  43 +import jakarta.validation.Valid;
  44 +import lombok.extern.slf4j.Slf4j;
  45 +import org.flowable.bpmn.constants.BpmnXMLConstants;
  46 +import org.flowable.bpmn.model.*;
  47 +import org.flowable.engine.HistoryService;
  48 +import org.flowable.engine.RuntimeService;
  49 +import org.flowable.engine.history.HistoricActivityInstance;
  50 +import org.flowable.engine.history.HistoricProcessInstance;
  51 +import org.flowable.engine.history.HistoricProcessInstanceQuery;
  52 +import org.flowable.engine.repository.ProcessDefinition;
  53 +import org.flowable.engine.runtime.ProcessInstance;
  54 +import org.flowable.task.api.history.HistoricTaskInstance;
  55 +import org.springframework.context.annotation.Lazy;
  56 +import org.springframework.stereotype.Service;
  57 +import org.springframework.transaction.annotation.Transactional;
  58 +import org.springframework.validation.annotation.Validated;
  59 +
  60 +import java.util.*;
  61 +
  62 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  63 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
  64 +import static cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmApprovalDetailRespVO.ActivityNode;
  65 +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*;
  66 +import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.START_USER_NODE_ID;
  67 +import static java.util.Arrays.asList;
  68 +import static java.util.Collections.singletonList;
  69 +import static org.flowable.bpmn.constants.BpmnXMLConstants.*;
  70 +
  71 +/**
  72 + * 流程实例 Service 实现类
  73 + * <p>
  74 + * ProcessDefinition & ProcessInstance & Execution & Task 的关系:
  75 + * 1. <a href="https://blog.csdn.net/bobozai86/article/details/105210414" />
  76 + * <p>
  77 + * HistoricProcessInstance & ProcessInstance 的关系:
  78 + * 1. <a href=" https://my.oschina.net/843294669/blog/71902" />
  79 + * <p>
  80 + * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例
  81 + *
  82 + * @author 芋道源码
  83 + */
  84 +@Service
  85 +@Validated
  86 +@Slf4j
  87 +public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService {
  88 +
  89 + @Resource
  90 + private RuntimeService runtimeService;
  91 + @Resource
  92 + private HistoryService historyService;
  93 +
  94 + @Resource
  95 + private BpmProcessDefinitionService processDefinitionService;
  96 + @Resource
  97 + @Lazy // 避免循环依赖
  98 + private BpmTaskService taskService;
  99 + @Resource
  100 + private BpmMessageService messageService;
  101 +
  102 + @Resource
  103 + private AdminUserApi adminUserApi;
  104 + @Resource
  105 + private DeptApi deptApi;
  106 +
  107 + @Resource
  108 + private BpmProcessInstanceEventPublisher processInstanceEventPublisher;
  109 +
  110 + @Resource
  111 + private BpmTaskCandidateInvoker taskCandidateInvoker;
  112 +
  113 + // ========== Query 查询相关方法 ==========
  114 +
  115 + @Override
  116 + public ProcessInstance getProcessInstance(String id) {
  117 + return runtimeService.createProcessInstanceQuery()
  118 + .includeProcessVariables()
  119 + .processInstanceId(id)
  120 + .singleResult();
  121 + }
  122 +
  123 + @Override
  124 + public List<ProcessInstance> getProcessInstances(Set<String> ids) {
  125 + return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list();
  126 + }
  127 +
  128 + @Override
  129 + public HistoricProcessInstance getHistoricProcessInstance(String id) {
  130 + return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).includeProcessVariables().singleResult();
  131 + }
  132 +
  133 + @Override
  134 + public List<HistoricProcessInstance> getHistoricProcessInstances(Set<String> ids) {
  135 + return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list();
  136 + }
  137 +
  138 + @Override
  139 + public PageResult<HistoricProcessInstance> getProcessInstancePage(Long userId,
  140 + BpmProcessInstancePageReqVO pageReqVO) {
  141 + // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页
  142 + HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery()
  143 + .includeProcessVariables()
  144 + .processInstanceTenantId(FlowableUtils.getTenantId())
  145 + .orderByProcessInstanceStartTime().desc();
  146 + if (userId != null) { // 【我的流程】菜单时,需要传递该字段
  147 + processInstanceQuery.startedBy(String.valueOf(userId));
  148 + } else if (pageReqVO.getStartUserId() != null) { // 【管理流程】菜单时,才会传递该字段
  149 + processInstanceQuery.startedBy(String.valueOf(pageReqVO.getStartUserId()));
  150 + }
  151 + if (StrUtil.isNotEmpty(pageReqVO.getName())) {
  152 + processInstanceQuery.processInstanceNameLike("%" + pageReqVO.getName() + "%");
  153 + }
  154 + if (StrUtil.isNotEmpty(pageReqVO.getProcessDefinitionKey())) {
  155 + processInstanceQuery.processDefinitionKey(pageReqVO.getProcessDefinitionKey());
  156 + }
  157 + if (StrUtil.isNotEmpty(pageReqVO.getCategory())) {
  158 + processInstanceQuery.processDefinitionCategory(pageReqVO.getCategory());
  159 + }
  160 + if (pageReqVO.getStatus() != null) {
  161 + processInstanceQuery.variableValueEquals(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS, pageReqVO.getStatus());
  162 + }
  163 + if (ArrayUtil.isNotEmpty(pageReqVO.getCreateTime())) {
  164 + processInstanceQuery.startedAfter(DateUtils.of(pageReqVO.getCreateTime()[0]));
  165 + processInstanceQuery.startedBefore(DateUtils.of(pageReqVO.getCreateTime()[1]));
  166 + }
  167 + // 查询数量
  168 + long processInstanceCount = processInstanceQuery.count();
  169 + if (processInstanceCount == 0) {
  170 + return PageResult.empty(processInstanceCount);
  171 + }
  172 + // 查询列表
  173 + List<HistoricProcessInstance> processInstanceList = processInstanceQuery.listPage(PageUtils.getStart(pageReqVO), pageReqVO.getPageSize());
  174 + return new PageResult<>(processInstanceList, processInstanceCount);
  175 + }
  176 +
  177 +
  178 + private Map<String, String> getFormFieldsPermission(BpmnModel bpmnModel,
  179 + String activityId, String taskId) {
  180 + // 1. 获取流程活动编号。流程活动 Id 为空事,从流程任务中获取流程活动 Id
  181 + if (StrUtil.isEmpty(activityId) && StrUtil.isNotEmpty(taskId)) {
  182 + activityId = Optional.ofNullable(taskService.getHistoricTask(taskId))
  183 + .map(HistoricTaskInstance::getTaskDefinitionKey).orElse(null);
  184 + }
  185 + if (StrUtil.isEmpty(activityId)) {
  186 + return null;
  187 + }
  188 +
  189 + // 2. 从 BpmnModel 中解析表单字段权限
  190 + return BpmnModelUtils.parseFormFieldsPermission(bpmnModel, activityId);
  191 + }
  192 +
  193 + @Override
  194 + public BpmApprovalDetailRespVO getApprovalDetail(Long loginUserId, BpmApprovalDetailReqVO reqVO) {
  195 + // 1.1 从 reqVO 中,读取公共变量
  196 + Long startUserId = loginUserId; // 流程发起人
  197 + HistoricProcessInstance historicProcessInstance = null; // 流程实例
  198 + Integer processInstanceStatus = BpmProcessInstanceStatusEnum.NOT_START.getStatus(); // 流程状态
  199 + Map<String, Object> processVariables = reqVO.getProcessVariables(); // 流程变量
  200 + // 1.2 如果是流程已发起的场景,则使用流程实例的数据
  201 + if (reqVO.getProcessInstanceId() != null) {
  202 + historicProcessInstance = getHistoricProcessInstance(reqVO.getProcessInstanceId());
  203 + if (historicProcessInstance == null) {
  204 + throw exception(ErrorCodeConstants.PROCESS_INSTANCE_NOT_EXISTS);
  205 + }
  206 + startUserId = Long.valueOf(historicProcessInstance.getStartUserId());
  207 + processInstanceStatus = FlowableUtils.getProcessInstanceStatus(historicProcessInstance);
  208 + processVariables = historicProcessInstance.getProcessVariables();
  209 + }
  210 + // 1.3 读取其它相关数据
  211 + ProcessDefinition processDefinition = processDefinitionService.getProcessDefinition(
  212 + historicProcessInstance != null ? historicProcessInstance.getProcessDefinitionId() : reqVO.getProcessDefinitionId());
  213 + BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService.getProcessDefinitionInfo(processDefinition.getId());
  214 + BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(processDefinition.getId());
  215 +
  216 + // 2.1 已结束 + 进行中的活动节点
  217 + List<ActivityNode> endActivityNodes = null; // 已结束的审批信息
  218 + List<ActivityNode> runActivityNodes = null; // 进行中的审批信息
  219 + List<HistoricActivityInstance> activities = null; // 流程实例列表
  220 + if (reqVO.getProcessInstanceId() != null) {
  221 + activities = taskService.getActivityListByProcessInstanceId(reqVO.getProcessInstanceId());
  222 + List<HistoricTaskInstance> tasks = taskService.getTaskListByProcessInstanceId(reqVO.getProcessInstanceId(), true);
  223 + endActivityNodes = getEndActivityNodeList(startUserId, bpmnModel, processDefinitionInfo,
  224 + historicProcessInstance, processInstanceStatus, activities, tasks);
  225 + runActivityNodes = getRunApproveNodeList(startUserId, bpmnModel, processDefinition, processVariables, activities, tasks);
  226 + }
  227 +
  228 + // 2.2 流程已经结束,直接 return,无需预测
  229 + if (BpmProcessInstanceStatusEnum.isProcessEndStatus(processInstanceStatus)) {
  230 + return buildApprovalDetail(reqVO, bpmnModel, processDefinition, processDefinitionInfo, historicProcessInstance,
  231 + processInstanceStatus, endActivityNodes, runActivityNodes, null, null);
  232 + }
  233 +
  234 + // 3.1 计算当前登录用户的待办任务
  235 + // TODO @jason:有一个极端情况,如果一个用户有 2 个 task A 和 B,A 已经通过,B 需要审核。这个时,通过 A 进来,todo 拿到 B,会不会表单权限不一致哈。
  236 + BpmTaskRespVO todoTask = taskService.getFirstTodoTask(loginUserId, reqVO.getProcessInstanceId());
  237 +
  238 + // 3.2 预测未运行节点的审批信息
  239 + List<ActivityNode> simulateActivityNodes = getSimulateApproveNodeList(startUserId, bpmnModel, processDefinitionInfo,
  240 + processVariables, activities);
  241 +
  242 + // 4. 拼接最终数据
  243 + return buildApprovalDetail(reqVO, bpmnModel, processDefinition, processDefinitionInfo, historicProcessInstance,
  244 + processInstanceStatus, endActivityNodes, runActivityNodes, simulateActivityNodes, todoTask);
  245 + }
  246 +
  247 + /**
  248 + * 拼接审批详情的最终数据
  249 + * <p>
  250 + * 主要是,拼接审批人的用户信息、部门信息
  251 + */
  252 + private BpmApprovalDetailRespVO buildApprovalDetail(BpmApprovalDetailReqVO reqVO,
  253 + BpmnModel bpmnModel,
  254 + ProcessDefinition processDefinition,
  255 + BpmProcessDefinitionInfoDO processDefinitionInfo,
  256 + HistoricProcessInstance processInstance,
  257 + Integer processInstanceStatus,
  258 + List<ActivityNode> endApprovalNodeInfos,
  259 + List<ActivityNode> runningApprovalNodeInfos,
  260 + List<ActivityNode> simulateApprovalNodeInfos,
  261 + BpmTaskRespVO todoTask) {
  262 + // 1. 获取所有需要读取用户信息的 userIds
  263 + List<ActivityNode> approveNodes = newArrayList(asList(endApprovalNodeInfos, runningApprovalNodeInfos, simulateApprovalNodeInfos));
  264 + Set<Long> userIds = BpmProcessInstanceConvert.INSTANCE.parseUserIds(processInstance, approveNodes, todoTask);
  265 + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
  266 + Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId));
  267 +
  268 + // 2. 表单权限
  269 + Map<String, String> formFieldsPermission = getFormFieldsPermission(bpmnModel, reqVO.getActivityId(), reqVO.getTaskId());
  270 +
  271 + // 3. 拼接数据
  272 + return BpmProcessInstanceConvert.INSTANCE.buildApprovalDetail(bpmnModel, processDefinition, processDefinitionInfo, processInstance,
  273 + processInstanceStatus, approveNodes, todoTask, formFieldsPermission, userMap, deptMap);
  274 + }
  275 +
  276 + /**
  277 + * 获得【已结束】的活动节点们
  278 + */
  279 + private List<ActivityNode> getEndActivityNodeList(Long startUserId, BpmnModel bpmnModel,
  280 + BpmProcessDefinitionInfoDO processDefinitionInfo,
  281 + HistoricProcessInstance historicProcessInstance, Integer processInstanceStatus,
  282 + List<HistoricActivityInstance> activities, List<HistoricTaskInstance> tasks) {
  283 + // 遍历 tasks 列表,只处理已结束的 UserTask
  284 + // 为什么不通过 activities 呢?因为,加签场景下,它只存在于 tasks,没有 activities,导致如果遍历 activities 的话,它无法成为一个节点
  285 + List<HistoricTaskInstance> endTasks = filterList(tasks, task -> task.getEndTime() != null);
  286 + List<ActivityNode> approvalNodes = convertList(endTasks, task -> {
  287 + FlowElement flowNode = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey());
  288 + ActivityNode activityNode = new ActivityNode().setId(task.getTaskDefinitionKey()).setName(task.getName())
  289 + .setNodeType(START_USER_NODE_ID.equals(task.getTaskDefinitionKey()) ?
  290 + BpmSimpleModelNodeType.START_USER_NODE.getType() : BpmSimpleModelNodeType.APPROVE_NODE.getType())
  291 + .setStatus(FlowableUtils.getTaskStatus(task))
  292 + .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(flowNode))
  293 + .setStartTime(DateUtils.of(task.getCreateTime())).setEndTime(DateUtils.of(task.getEndTime()))
  294 + .setTasks(singletonList(BpmProcessInstanceConvert.INSTANCE.buildApprovalTaskInfo(task)));
  295 + // 如果是取消状态,则跳过
  296 + if (BpmTaskStatusEnum.isCancelStatus(activityNode.getStatus())) {
  297 + return null;
  298 + }
  299 + return activityNode;
  300 + });
  301 +
  302 + // 遍历 activities,只处理已结束的 StartEvent、EndEvent
  303 + List<HistoricActivityInstance> endActivities = filterList(activities, activity -> activity.getEndTime() != null
  304 + && (StrUtil.equalsAny(activity.getActivityType(), ELEMENT_EVENT_START, ELEMENT_EVENT_END)));
  305 + endActivities.forEach(activity -> {
  306 + // StartEvent:只处理 BPMN 的场景。因为,SIMPLE 情况下,已经有 START_USER_NODE 节点
  307 + if (ELEMENT_EVENT_START.equals(activity.getActivityType())
  308 + && BpmModelTypeEnum.BPMN.getType().equals(processDefinitionInfo.getModelType())) {
  309 + ActivityNodeTask startTask = new ActivityNodeTask().setId(BpmnModelConstants.START_USER_NODE_ID)
  310 + .setAssignee(startUserId).setStatus(BpmTaskStatusEnum.APPROVE.getStatus());
  311 + ActivityNode startNode = new ActivityNode().setId(startTask.getId())
  312 + .setName(BpmSimpleModelNodeType.START_USER_NODE.getName())
  313 + .setNodeType(BpmSimpleModelNodeType.START_USER_NODE.getType())
  314 + .setStatus(startTask.getStatus()).setTasks(ListUtil.of(startTask))
  315 + .setStartTime(DateUtils.of(activity.getStartTime())).setEndTime(DateUtils.of(activity.getEndTime()));
  316 + approvalNodes.add(0, startNode);
  317 + return;
  318 + }
  319 + // EndEvent
  320 + if (ELEMENT_EVENT_END.equals(activity.getActivityType())) {
  321 + if (BpmProcessInstanceStatusEnum.isRejectStatus(processInstanceStatus)) {
  322 + // 拒绝情况下,不需要展示 EndEvent 结束节点。原因是:前端已经展示 x 效果,无需重复展示
  323 + return;
  324 + }
  325 + ActivityNode endNode = new ActivityNode().setId(activity.getId())
  326 + .setName(BpmSimpleModelNodeType.END_NODE.getName())
  327 + .setNodeType(BpmSimpleModelNodeType.END_NODE.getType()).setStatus(processInstanceStatus)
  328 + .setStartTime(DateUtils.of(activity.getStartTime())).setEndTime(DateUtils.of(activity.getEndTime()));
  329 + String reason = FlowableUtils.getProcessInstanceReason(historicProcessInstance);
  330 + if (StrUtil.isNotEmpty(reason)) {
  331 + endNode.setTasks(singletonList(new ActivityNodeTask().setId(endNode.getId())
  332 + .setStatus(endNode.getStatus()).setReason(reason)));
  333 + }
  334 + approvalNodes.add(endNode);
  335 + }
  336 + });
  337 + return approvalNodes;
  338 + }
  339 +
  340 + /**
  341 + * 获得【进行中】的活动节点们
  342 + */
  343 + private List<ActivityNode> getRunApproveNodeList(Long startUserId,
  344 + BpmnModel bpmnModel,
  345 + ProcessDefinition processDefinition,
  346 + Map<String, Object> processVariables,
  347 + List<HistoricActivityInstance> activities,
  348 + List<HistoricTaskInstance> tasks) {
  349 + // 构建运行中的任务,基于 activityId 分组
  350 + List<HistoricActivityInstance> runActivities = filterList(activities, activity -> activity.getEndTime() == null
  351 + && (StrUtil.equalsAny(activity.getActivityType(), ELEMENT_TASK_USER)));
  352 + Map<String, List<HistoricActivityInstance>> runningTaskMap = convertMultiMap(runActivities, HistoricActivityInstance::getActivityId);
  353 +
  354 + // 按照 activityId 分组,构建 ApprovalNodeInfo 节点
  355 + Map<String, HistoricTaskInstance> taskMap = convertMap(tasks, HistoricTaskInstance::getId);
  356 + return convertList(runningTaskMap.entrySet(), entry -> {
  357 + String activityId = entry.getKey();
  358 + List<HistoricActivityInstance> taskActivities = entry.getValue();
  359 + // 构建活动节点
  360 + FlowElement flowNode = BpmnModelUtils.getFlowElementById(bpmnModel, activityId);
  361 + HistoricActivityInstance firstActivity = CollUtil.getFirst(taskActivities); // 取第一个任务,会签/或签的任务,开始时间相同
  362 + ActivityNode activityNode = new ActivityNode().setId(firstActivity.getActivityId()).setName(firstActivity.getActivityName())
  363 + .setNodeType(BpmSimpleModelNodeType.APPROVE_NODE.getType()).setStatus(BpmTaskStatusEnum.RUNNING.getStatus())
  364 + .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(flowNode))
  365 + .setStartTime(DateUtils.of(CollUtil.getFirst(taskActivities).getStartTime()))
  366 + .setTasks(new ArrayList<>());
  367 + // 处理每个任务的 tasks 属性
  368 + for (HistoricActivityInstance activity : taskActivities) {
  369 + HistoricTaskInstance task = taskMap.get(activity.getTaskId());
  370 + activityNode.getTasks().add(BpmProcessInstanceConvert.INSTANCE.buildApprovalTaskInfo(task));
  371 + // 加签子任务,需要过滤掉已经完成的加签子任务
  372 + List<HistoricTaskInstance> childrenTasks = filterList(
  373 + taskService.getAllChildrenTaskListByParentTaskId(activity.getTaskId(), tasks),
  374 + childTask -> childTask.getEndTime() == null);
  375 + if (CollUtil.isNotEmpty(childrenTasks)) {
  376 + activityNode.getTasks().addAll(convertList(childrenTasks, BpmProcessInstanceConvert.INSTANCE::buildApprovalTaskInfo));
  377 + }
  378 + }
  379 + // 处理每个任务的 candidateUsers 属性:如果是依次审批,需要预测它的后续审批人。因为 Task 是审批完一个,创建一个新的 Task
  380 + if (BpmnModelUtils.isSequentialUserTask(flowNode)) {
  381 + List<Long> candidateUserIds = getTaskCandidateUserList(bpmnModel, flowNode.getId(),
  382 + startUserId, processDefinition.getId(), processVariables);
  383 + // 截取当前审批人位置后面的候选人,不包含当前审批人
  384 + ActivityNodeTask approvalTaskInfo = CollUtil.getFirst(activityNode.getTasks());
  385 + Assert.notNull(approvalTaskInfo, "任务不能为空");
  386 + int index = CollUtil.indexOf(candidateUserIds, userId -> ObjectUtils.equalsAny(userId, approvalTaskInfo.getOwner(),
  387 + approvalTaskInfo.getAssignee())); // 委派或者向前加签情况,需要先比较 owner
  388 + activityNode.setCandidateUserIds(CollUtil.sub(candidateUserIds, index + 1, candidateUserIds.size()));
  389 + }
  390 + return activityNode;
  391 + });
  392 + }
  393 +
  394 + /**
  395 + * 获得【预测(未来)】的活动节点们
  396 + */
  397 + private List<ActivityNode> getSimulateApproveNodeList(Long startUserId, BpmnModel bpmnModel,
  398 + BpmProcessDefinitionInfoDO processDefinitionInfo,
  399 + Map<String, Object> processVariables,
  400 + List<HistoricActivityInstance> activities) {
  401 + // TODO @芋艿:【可优化】在驳回场景下,未来的预测准确性不高。原因是,驳回后,HistoricActivityInstance 包括了历史的操作,不是只有 startEvent 到当前节点的记录
  402 + Set<String> runActivityIds = convertSet(activities, HistoricActivityInstance::getActivityId);
  403 + // 情况一:BPMN 设计器
  404 + if (Objects.equals(BpmModelTypeEnum.BPMN.getType(), processDefinitionInfo.getModelType())) {
  405 + List<FlowElement> flowElements = BpmnModelUtils.simulateProcess(bpmnModel, processVariables);
  406 + return convertList(flowElements, flowElement -> buildNotRunApproveNodeForBpmn(startUserId, bpmnModel,
  407 + processDefinitionInfo, processVariables, flowElement, runActivityIds));
  408 + }
  409 + // 情况二:SIMPLE 设计器
  410 + if (Objects.equals(BpmModelTypeEnum.SIMPLE.getType(), processDefinitionInfo.getModelType())) {
  411 + BpmSimpleModelNodeVO simpleModel = JsonUtils.parseObject(processDefinitionInfo.getSimpleModel(), BpmSimpleModelNodeVO.class);
  412 + List<BpmSimpleModelNodeVO> simpleNodes = SimpleModelUtils.simulateProcess(simpleModel, processVariables);
  413 + return convertList(simpleNodes, simpleNode -> buildNotRunApproveNodeForSimple(startUserId, bpmnModel,
  414 + processDefinitionInfo, processVariables, simpleNode, runActivityIds));
  415 + }
  416 + throw new IllegalArgumentException("未知设计器类型:" + processDefinitionInfo.getModelType());
  417 + }
  418 +
  419 + private ActivityNode buildNotRunApproveNodeForSimple(Long startUserId, BpmnModel bpmnModel,
  420 + BpmProcessDefinitionInfoDO processDefinitionInfo, Map<String, Object> processVariables,
  421 + BpmSimpleModelNodeVO node, Set<String> runActivityIds) {
  422 + // TODO @芋艿:【可优化】在驳回场景下,未来的预测准确性不高。原因是,驳回后,HistoricActivityInstance 包括了历史的操作,不是只有 startEvent 到当前节点的记录
  423 + if (runActivityIds.contains(node.getId())) {
  424 + return null;
  425 + }
  426 +
  427 + ActivityNode activityNode = new ActivityNode().setId(node.getId()).setName(node.getName())
  428 + .setNodeType(node.getType()).setCandidateStrategy(node.getCandidateStrategy())
  429 + .setStatus(BpmTaskStatusEnum.NOT_START.getStatus());
  430 +
  431 + // 1. 开始节点/审批节点
  432 + if (ObjectUtils.equalsAny(node.getType(),
  433 + BpmSimpleModelNodeType.START_USER_NODE.getType(),
  434 + BpmSimpleModelNodeType.APPROVE_NODE.getType())) {
  435 + List<Long> candidateUserIds = getTaskCandidateUserList(bpmnModel, node.getId(),
  436 + startUserId, processDefinitionInfo.getProcessDefinitionId(), processVariables);
  437 + activityNode.setCandidateUserIds(candidateUserIds);
  438 + return activityNode;
  439 + }
  440 +
  441 + // 2. 结束节点
  442 + if (BpmSimpleModelNodeType.END_NODE.getType().equals(node.getType())) {
  443 + return activityNode;
  444 + }
  445 +
  446 + // 3. 抄送节点
  447 + if (CollUtil.isEmpty(runActivityIds) && // 流程发起时:需要展示抄送节点,用于选择抄送人
  448 + BpmSimpleModelNodeType.COPY_NODE.getType().equals(node.getType())) {
  449 + return activityNode;
  450 + }
  451 + return null;
  452 + }
  453 +
  454 + private ActivityNode buildNotRunApproveNodeForBpmn(Long startUserId, BpmnModel bpmnModel,
  455 + BpmProcessDefinitionInfoDO processDefinitionInfo, Map<String, Object> processVariables,
  456 + FlowElement node, Set<String> runActivityIds) {
  457 + if (runActivityIds.contains(node.getId())) {
  458 + return null;
  459 + }
  460 + ActivityNode activityNode = new ActivityNode().setId(node.getId()).setStatus(BpmTaskStatusEnum.NOT_START.getStatus());
  461 +
  462 + // 1. 开始节点
  463 + if (node instanceof StartEvent) {
  464 + return activityNode.setName(BpmSimpleModelNodeType.START_USER_NODE.getName())
  465 + .setNodeType(BpmSimpleModelNodeType.START_USER_NODE.getType());
  466 + }
  467 +
  468 + // 2. 审批节点
  469 + if (node instanceof UserTask) {
  470 + List<Long> candidateUserIds = getTaskCandidateUserList(bpmnModel, node.getId(),
  471 + startUserId, processDefinitionInfo.getProcessDefinitionId(), processVariables);
  472 + return activityNode.setName(node.getName()).setNodeType(BpmSimpleModelNodeType.APPROVE_NODE.getType())
  473 + .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(node))
  474 + .setCandidateUserIds(candidateUserIds);
  475 + }
  476 +
  477 + // 3. 结束节点
  478 + if (node instanceof EndEvent) {
  479 + return activityNode.setName(BpmSimpleModelNodeType.END_NODE.getName())
  480 + .setNodeType(BpmSimpleModelNodeType.END_NODE.getType());
  481 + }
  482 + return null;
  483 + }
  484 +
  485 + private List<Long> getTaskCandidateUserList(BpmnModel bpmnModel, String activityId,
  486 + Long startUserId, String processDefinitionId, Map<String, Object> processVariables) {
  487 + Set<Long> userIds = taskCandidateInvoker.calculateUsersByActivity(bpmnModel, activityId,
  488 + startUserId, processDefinitionId, processVariables);
  489 + return new ArrayList<>(userIds);
  490 + }
  491 +
  492 + @Override
  493 + public BpmProcessInstanceBpmnModelViewRespVO getProcessInstanceBpmnModelView(String id) {
  494 + // 1.1 获得流程实例
  495 + HistoricProcessInstance processInstance = getHistoricProcessInstance(id);
  496 + if (processInstance == null) {
  497 + return null;
  498 + }
  499 + // 1.2 获得流程定义
  500 + BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(processInstance.getProcessDefinitionId());
  501 + if (bpmnModel == null) {
  502 + return null;
  503 + }
  504 + BpmSimpleModelNodeVO simpleModel = null;
  505 + BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService.getProcessDefinitionInfo(
  506 + processInstance.getProcessDefinitionId());
  507 + if (processDefinitionInfo != null && BpmModelTypeEnum.SIMPLE.getType().equals(processDefinitionInfo.getModelType())) {
  508 + simpleModel = JsonUtils.parseObject(processDefinitionInfo.getSimpleModel(), BpmSimpleModelNodeVO.class);
  509 + }
  510 + // 1.3 获得流程实例对应的活动实例列表 + 任务列表
  511 + List<HistoricActivityInstance> activities = taskService.getActivityListByProcessInstanceId(id);
  512 + List<HistoricTaskInstance> tasks = taskService.getTaskListByProcessInstanceId(id, true);
  513 +
  514 + // 2.1 拼接进度信息
  515 + Set<String> unfinishedTaskActivityIds = convertSet(activities, HistoricActivityInstance::getActivityId,
  516 + activityInstance -> activityInstance.getEndTime() == null);
  517 + Set<String> finishedTaskActivityIds = convertSet(activities, HistoricActivityInstance::getActivityId,
  518 + activityInstance -> activityInstance.getEndTime() != null
  519 + && ObjectUtil.notEqual(activityInstance.getActivityType(), BpmnXMLConstants.ELEMENT_SEQUENCE_FLOW));
  520 + Set<String> finishedSequenceFlowActivityIds = convertSet(activities, HistoricActivityInstance::getActivityId,
  521 + activityInstance -> activityInstance.getEndTime() != null
  522 + && ObjectUtil.equals(activityInstance.getActivityType(), BpmnXMLConstants.ELEMENT_SEQUENCE_FLOW));
  523 + // 特殊:会签情况下,会有部分已完成(审批)、部分未完成(待审批),此时需要 finishedTaskActivityIds 移除掉
  524 + finishedTaskActivityIds.removeAll(unfinishedTaskActivityIds);
  525 + // 特殊:如果流程实例被拒绝,则需要计算是哪个活动节点。
  526 + // 注意,只取最后一个。因为会存在多次拒绝的情况,拒绝驳回到指定节点
  527 + Set<String> rejectTaskActivityIds = CollUtil.newHashSet();
  528 + if (BpmProcessInstanceStatusEnum.isRejectStatus(FlowableUtils.getProcessInstanceStatus(processInstance))) {
  529 + tasks.stream()
  530 + .filter(task -> BpmTaskStatusEnum.isRejectStatus(FlowableUtils.getTaskStatus(task)))
  531 + .max(Comparator.comparing(HistoricTaskInstance::getEndTime))
  532 + .ifPresent(reject -> rejectTaskActivityIds.add(reject.getTaskDefinitionKey()));
  533 + finishedTaskActivityIds.removeAll(rejectTaskActivityIds);
  534 + }
  535 +
  536 + // 2.2 拼接基础信息
  537 + Set<Long> userIds = BpmProcessInstanceConvert.INSTANCE.parseUserIds02(processInstance, tasks);
  538 + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
  539 + Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId));
  540 + return BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceBpmnModelView(processInstance, tasks, bpmnModel, simpleModel,
  541 + unfinishedTaskActivityIds, finishedTaskActivityIds, finishedSequenceFlowActivityIds, rejectTaskActivityIds,
  542 + userMap, deptMap);
  543 + }
  544 +
  545 + // ========== Update 写入相关方法 ==========
  546 +
  547 + @Override
  548 + @Transactional(rollbackFor = Exception.class)
  549 + public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) {
  550 + // 获得流程定义
  551 + ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId());
  552 + // 发起流程
  553 + return createProcessInstance0(userId, definition, createReqVO.getVariables(), null,
  554 + createReqVO.getStartUserSelectAssignees());
  555 + }
  556 +
  557 + @Override
  558 + public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) {
  559 + // 获得流程定义
  560 + ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey());
  561 + // 发起流程
  562 + return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(),
  563 + createReqDTO.getStartUserSelectAssignees());
  564 + }
  565 +
  566 + private String createProcessInstance0(Long userId, ProcessDefinition definition,
  567 + Map<String, Object> variables, String businessKey,
  568 + Map<String, List<Long>> startUserSelectAssignees) {
  569 + // 1.1 校验流程定义
  570 + if (definition == null) {
  571 + throw exception(PROCESS_DEFINITION_NOT_EXISTS);
  572 + }
  573 + if (definition.isSuspended()) {
  574 + throw exception(PROCESS_DEFINITION_IS_SUSPENDED);
  575 + }
  576 + BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService.getProcessDefinitionInfo(definition.getId());
  577 + if (processDefinitionInfo == null) {
  578 + throw exception(PROCESS_DEFINITION_NOT_EXISTS);
  579 + }
  580 + // 1.2 校验是否能够发起
  581 + if (!processDefinitionService.canUserStartProcessDefinition(processDefinitionInfo, userId)) {
  582 + throw exception(PROCESS_INSTANCE_START_USER_CAN_START);
  583 + }
  584 + // 1.3 校验发起人自选审批人
  585 + validateStartUserSelectAssignees(definition, startUserSelectAssignees);
  586 +
  587 + // 2. 创建流程实例
  588 + if (variables == null) {
  589 + variables = new HashMap<>();
  590 + }
  591 + FlowableUtils.filterProcessInstanceFormVariable(variables); // 过滤一下,避免 ProcessInstance 系统级的变量被占用
  592 + variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_ID, userId); // 设置流程变量,发起人 ID
  593 + variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS, // 流程实例状态:审批中
  594 + BpmProcessInstanceStatusEnum.RUNNING.getStatus());
  595 + if (CollUtil.isNotEmpty(startUserSelectAssignees)) {
  596 + variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES, startUserSelectAssignees);
  597 + }
  598 + ProcessInstance instance = runtimeService.createProcessInstanceBuilder()
  599 + .processDefinitionId(definition.getId())
  600 + .businessKey(businessKey)
  601 + .name(definition.getName().trim())
  602 + .variables(variables)
  603 + .start();
  604 + return instance.getId();
  605 + }
  606 +
  607 + private void validateStartUserSelectAssignees(ProcessDefinition definition, Map<String, List<Long>> startUserSelectAssignees) {
  608 + // 1. 获得发起人自选审批人的 UserTask/ServiceTask 列表
  609 + BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(definition.getId());
  610 + List<Task> tasks = BpmTaskCandidateStartUserSelectStrategy.getStartUserSelectTaskList(bpmnModel);
  611 + if (CollUtil.isEmpty(tasks)) {
  612 + return;
  613 + }
  614 +
  615 + // 2. 校验发起人自选审批人的审批人和抄送人是否都配置了
  616 + tasks.forEach(task -> {
  617 + List<Long> assignees = startUserSelectAssignees != null ? startUserSelectAssignees.get(task.getId()) : null;
  618 + if (CollUtil.isEmpty(assignees)) {
  619 + throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_CONFIG, task.getName());
  620 + }
  621 + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(assignees);
  622 + assignees.forEach(assignee -> {
  623 + if (userMap.get(assignee) == null) {
  624 + throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_EXISTS, task.getName(), assignee);
  625 + }
  626 + });
  627 + });
  628 + }
  629 +
  630 + @Override
  631 + public void cancelProcessInstanceByStartUser(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) {
  632 + // 1.1 校验流程实例存在
  633 + ProcessInstance instance = getProcessInstance(cancelReqVO.getId());
  634 + if (instance == null) {
  635 + throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS);
  636 + }
  637 + // 1.2 只能取消自己的
  638 + if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) {
  639 + throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF);
  640 + }
  641 +
  642 + // 2. 取消流程
  643 + updateProcessInstanceCancel(cancelReqVO.getId(),
  644 + BpmReasonEnum.CANCEL_PROCESS_INSTANCE_BY_START_USER.format(cancelReqVO.getReason()));
  645 + }
  646 +
  647 + @Override
  648 + public void cancelProcessInstanceByAdmin(Long userId, BpmProcessInstanceCancelReqVO cancelReqVO) {
  649 + // 1.1 校验流程实例存在
  650 + ProcessInstance instance = getProcessInstance(cancelReqVO.getId());
  651 + if (instance == null) {
  652 + throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS);
  653 + }
  654 +
  655 + // 2. 取消流程
  656 + AdminUserRespDTO user = adminUserApi.getUser(userId);
  657 + updateProcessInstanceCancel(cancelReqVO.getId(),
  658 + BpmReasonEnum.CANCEL_PROCESS_INSTANCE_BY_ADMIN.format(user.getNickname(), cancelReqVO.getReason()));
  659 + }
  660 +
  661 + private void updateProcessInstanceCancel(String id, String reason) {
  662 + // 1. 更新流程实例 status
  663 + runtimeService.setVariable(id, BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS,
  664 + BpmProcessInstanceStatusEnum.CANCEL.getStatus());
  665 + runtimeService.setVariable(id, BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_REASON, reason);
  666 +
  667 + // 2. 结束流程
  668 + taskService.moveTaskToEnd(id);
  669 + }
  670 +
  671 + @Override
  672 + public void updateProcessInstanceReject(ProcessInstance processInstance, String reason) {
  673 + runtimeService.setVariable(processInstance.getProcessInstanceId(), BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS,
  674 + BpmProcessInstanceStatusEnum.REJECT.getStatus());
  675 + runtimeService.setVariable(processInstance.getProcessInstanceId(), BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_REASON,
  676 + BpmReasonEnum.REJECT_TASK.format(reason));
  677 + }
  678 +
  679 + // ========== Event 事件相关方法 ==========
  680 +
  681 + @Override
  682 + public void processProcessInstanceCompleted(ProcessInstance instance) {
  683 + // 注意:需要基于 instance 设置租户编号,避免 Flowable 内部异步时,丢失租户编号
  684 + FlowableUtils.execute(instance.getTenantId(), () -> {
  685 + // 1.1 获取当前状态
  686 + Integer status = (Integer) instance.getProcessVariables().get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS);
  687 + String reason = (String) instance.getProcessVariables().get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_REASON);
  688 + // 1.2 当流程状态还是审批状态中,说明审批通过了,则变更下它的状态
  689 + // 为什么这么处理?因为流程完成,并且完成了,说明审批通过了
  690 + if (Objects.equals(status, BpmProcessInstanceStatusEnum.RUNNING.getStatus())) {
  691 + status = BpmProcessInstanceStatusEnum.APPROVE.getStatus();
  692 + runtimeService.setVariable(instance.getId(), BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS, status);
  693 + }
  694 +
  695 + // 2. 发送对应的消息通知
  696 + if (Objects.equals(status, BpmProcessInstanceStatusEnum.APPROVE.getStatus())) {
  697 + messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceApproveMessage(instance));
  698 + } else if (Objects.equals(status, BpmProcessInstanceStatusEnum.REJECT.getStatus())) {
  699 + messageService.sendMessageWhenProcessInstanceReject(
  700 + BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceRejectMessage(instance, reason));
  701 + }
  702 +
  703 + // 3. 发送流程实例的状态事件
  704 + processInstanceEventPublisher.sendProcessInstanceResultEvent(
  705 + BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, instance, status));
  706 + });
  707 + }
  708 +
  709 +}
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
... ... @@ -12,6 +12,7 @@ import cn.iocoder.yudao.framework.common.util.object.PageUtils;
12 12 import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
13 13 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*;
14 14 import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert;
  15 +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO;
15 16 import cn.iocoder.yudao.module.bpm.enums.definition.*;
16 17 import cn.iocoder.yudao.module.bpm.enums.task.BpmCommentTypeEnum;
17 18 import cn.iocoder.yudao.module.bpm.enums.task.BpmReasonEnum;
... ... @@ -20,6 +21,7 @@ import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum;
20 21 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants;
21 22 import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
22 23 import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
  24 +import cn.iocoder.yudao.module.bpm.service.definition.BpmFormService;
23 25 import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService;
24 26 import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService;
25 27 import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService;
... ... @@ -91,6 +93,8 @@ public class BpmTaskServiceImpl implements BpmTaskService {
91 93 private BpmModelService modelService;
92 94 @Resource
93 95 private BpmMessageService messageService;
  96 + @Resource
  97 + private BpmFormService formService;
94 98  
95 99 @Resource
96 100 private AdminUserApi adminUserApi;
... ... @@ -109,6 +113,9 @@ public class BpmTaskServiceImpl implements BpmTaskService {
109 113 if (StrUtil.isNotBlank(pageVO.getName())) {
110 114 taskQuery.taskNameLike("%" + pageVO.getName() + "%");
111 115 }
  116 + if (StrUtil.isNotEmpty(pageVO.getCategory())) {
  117 + taskQuery.taskCategory(pageVO.getCategory());
  118 + }
112 119 if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) {
113 120 taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[0]));
114 121 taskQuery.taskCreatedBefore(DateUtils.of(pageVO.getCreateTime()[1]));
... ... @@ -153,7 +160,13 @@ public class BpmTaskServiceImpl implements BpmTaskService {
153 160 BpmnModel bpmnModel = bpmProcessDefinitionService.getProcessDefinitionBpmnModel(todoTask.getProcessDefinitionId());
154 161 Map<Integer, BpmTaskRespVO.OperationButtonSetting> buttonsSetting = BpmnModelUtils.parseButtonsSetting(
155 162 bpmnModel, todoTask.getTaskDefinitionKey());
156   - return BpmTaskConvert.INSTANCE.buildTodoTask(todoTask, childrenTasks, buttonsSetting);
  163 +
  164 + // 4. 任务表单
  165 + BpmFormDO taskForm = null;
  166 + if (StrUtil.isNotBlank(todoTask.getFormKey())){
  167 + taskForm = formService.getForm(NumberUtils.parseLong(todoTask.getFormKey()));
  168 + }
  169 + return BpmTaskConvert.INSTANCE.buildTodoTask(todoTask, childrenTasks, buttonsSetting, taskForm);
157 170 }
158 171  
159 172 @Override
... ... @@ -188,6 +201,9 @@ public class BpmTaskServiceImpl implements BpmTaskService {
188 201 if (StrUtil.isNotBlank(pageVO.getName())) {
189 202 taskQuery.taskNameLike("%" + pageVO.getName() + "%");
190 203 }
  204 + if (StrUtil.isNotEmpty(pageVO.getCategory())) {
  205 + taskQuery.taskCategory(pageVO.getCategory());
  206 + }
191 207 if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) {
192 208 taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[0]));
193 209 taskQuery.taskCreatedBefore(DateUtils.of(pageVO.getCreateTime()[1]));
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/other/BpmTaskCandidateExpressionStrategyTest.java
... ... @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.o
3 3 import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
4 4 import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
5 5 import org.flowable.engine.delegate.DelegateExecution;
  6 +import org.junit.jupiter.api.Disabled;
6 7 import org.junit.jupiter.api.Test;
7 8 import org.mockito.InjectMocks;
8 9 import org.mockito.MockedStatic;
... ... @@ -16,6 +17,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
16 17 import static org.mockito.ArgumentMatchers.eq;
17 18 import static org.mockito.Mockito.*;
18 19  
  20 +@Disabled // TODO 芋艿:临时注释
19 21 public class BpmTaskCandidateExpressionStrategyTest extends BaseMockitoUnitTest {
20 22  
21 23 @InjectMocks
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/user/BpmTaskCandidateGroupStrategyTest.java
... ... @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.u
3 3 import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
4 4 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO;
5 5 import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService;
  6 +import org.junit.jupiter.api.Disabled;
6 7 import org.junit.jupiter.api.Test;
7 8 import org.mockito.InjectMocks;
8 9 import org.mockito.Mock;
... ... @@ -16,6 +17,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
16 17 import static org.mockito.ArgumentMatchers.eq;
17 18 import static org.mockito.Mockito.when;
18 19  
  20 +@Disabled // TODO 芋艿:临时注释
19 21 public class BpmTaskCandidateGroupStrategyTest extends BaseMockitoUnitTest {
20 22  
21 23 @InjectMocks
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/user/BpmTaskCandidatePostStrategyTest.java
... ... @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
4 4 import cn.iocoder.yudao.module.system.api.dept.PostApi;
5 5 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
6 6 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
  7 +import org.junit.jupiter.api.Disabled;
7 8 import org.junit.jupiter.api.Test;
8 9 import org.mockito.InjectMocks;
9 10 import org.mockito.Mock;
... ... @@ -17,6 +18,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
17 18 import static org.mockito.ArgumentMatchers.eq;
18 19 import static org.mockito.Mockito.when;
19 20  
  21 +@Disabled // TODO 芋艿:临时注释
20 22 public class BpmTaskCandidatePostStrategyTest extends BaseMockitoUnitTest {
21 23  
22 24 @InjectMocks
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/user/BpmTaskCandidateRoleStrategyTest.java
... ... @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.u
3 3 import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
4 4 import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
5 5 import cn.iocoder.yudao.module.system.api.permission.RoleApi;
  6 +import org.junit.jupiter.api.Disabled;
6 7 import org.junit.jupiter.api.Test;
7 8 import org.mockito.InjectMocks;
8 9 import org.mockito.Mock;
... ... @@ -14,6 +15,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
14 15 import static org.mockito.ArgumentMatchers.eq;
15 16 import static org.mockito.Mockito.when;
16 17  
  18 +@Disabled // TODO 芋艿:临时注释
17 19 public class BpmTaskCandidateRoleStrategyTest extends BaseMockitoUnitTest {
18 20  
19 21 @InjectMocks
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/user/BpmTaskCandidateUserStrategyTest.java
1 1 package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user;
2 2  
3 3 import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
  4 +import org.junit.jupiter.api.Disabled;
4 5 import org.junit.jupiter.api.Test;
5 6 import org.mockito.InjectMocks;
6 7  
... ... @@ -9,6 +10,7 @@ import java.util.Set;
9 10 import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
10 11 import static org.junit.jupiter.api.Assertions.assertEquals;
11 12  
  13 +@Disabled // TODO 芋艿:临时注释
12 14 public class BpmTaskCandidateUserStrategyTest extends BaseMockitoUnitTest {
13 15  
14 16 @InjectMocks
... ...
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/payment/ErpFinancePaymentRespVO.java
1 1 package cn.iocoder.yudao.module.erp.controller.admin.finance.vo.payment;
2 2  
  3 +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
3 4 import com.alibaba.excel.annotation.ExcelProperty;
4 5 import io.swagger.v3.oas.annotations.media.Schema;
5 6 import jakarta.validation.constraints.NotNull;
... ... @@ -11,6 +12,7 @@ import java.util.List;
11 12  
12 13 @Schema(description = "管理后台 - ERP 付款单 Response VO")
13 14 @Data
  15 +@ExcelIgnoreUnannotated
14 16 public class ErpFinancePaymentRespVO {
15 17  
16 18 @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23752")
... ...
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/vo/receipt/ErpFinanceReceiptRespVO.java
1 1 package cn.iocoder.yudao.module.erp.controller.admin.finance.vo.receipt;
2 2  
  3 +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
3 4 import com.alibaba.excel.annotation.ExcelProperty;
4 5 import io.swagger.v3.oas.annotations.media.Schema;
5 6 import jakarta.validation.constraints.NotNull;
... ... @@ -11,6 +12,7 @@ import java.util.List;
11 12  
12 13 @Schema(description = "管理后台 - ERP 收款单 Response VO")
13 14 @Data
  15 +@ExcelIgnoreUnannotated
14 16 public class ErpFinanceReceiptRespVO {
15 17  
16 18 @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23752")
... ...
yudao-module-infra/yudao-module-infra-biz/pom.xml
... ... @@ -116,8 +116,8 @@
116 116 <artifactId>jsch</artifactId> <!-- 文件客户端:解决 sftp 连接 -->
117 117 </dependency>
118 118 <dependency>
119   - <groupId>io.minio</groupId>
120   - <artifactId>minio</artifactId> <!-- 文件客户端:解决阿里云、腾讯云、minio 等 S3 连接 -->
  119 + <groupId>com.amazonaws</groupId>
  120 + <artifactId>aws-java-sdk-s3</artifactId><!-- 文件客户端:解决阿里云、腾讯云、minio 等 S3 连接 -->
121 121 </dependency>
122 122  
123 123 <dependency>
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java
... ... @@ -4,10 +4,17 @@ import cn.hutool.core.io.IoUtil;
4 4 import cn.hutool.core.util.StrUtil;
5 5 import cn.hutool.http.HttpUtil;
6 6 import cn.iocoder.yudao.module.infra.framework.file.core.client.AbstractFileClient;
7   -import io.minio.*;
8   -import io.minio.http.Method;
  7 +import com.amazonaws.HttpMethod;
  8 +import com.amazonaws.auth.AWSStaticCredentialsProvider;
  9 +import com.amazonaws.auth.BasicAWSCredentials;
  10 +import com.amazonaws.client.builder.AwsClientBuilder;
  11 +import com.amazonaws.services.s3.AmazonS3Client;
  12 +import com.amazonaws.services.s3.AmazonS3ClientBuilder;
  13 +import com.amazonaws.services.s3.model.ObjectMetadata;
  14 +import com.amazonaws.services.s3.model.S3Object;
9 15  
10 16 import java.io.ByteArrayInputStream;
  17 +import java.util.Date;
11 18 import java.util.concurrent.TimeUnit;
12 19  
13 20 /**
... ... @@ -19,7 +26,7 @@ import java.util.concurrent.TimeUnit;
19 26 */
20 27 public class S3FileClient extends AbstractFileClient<S3FileClientConfig> {
21 28  
22   - private MinioClient client;
  29 + private AmazonS3Client client;
23 30  
24 31 public S3FileClient(Long id, S3FileClientConfig config) {
25 32 super(id, config);
... ... @@ -32,25 +39,30 @@ public class S3FileClient extends AbstractFileClient&lt;S3FileClientConfig&gt; {
32 39 config.setDomain(buildDomain());
33 40 }
34 41 // 初始化客户端
35   - client = MinioClient.builder()
36   - .endpoint(buildEndpointURL()) // Endpoint URL
37   - .region(buildRegion()) // Region
38   - .credentials(config.getAccessKey(), config.getAccessSecret()) // 认证密钥
  42 + client = (AmazonS3Client)AmazonS3ClientBuilder.standard()
  43 + .withCredentials(buildCredentials())
  44 + .withEndpointConfiguration(buildEndpointConfiguration())
39 45 .build();
40   - enableVirtualStyleEndpoint();
41 46 }
42 47  
43 48 /**
44   - * 基于 endpoint 构建调用云服务的 URL 地址
  49 + * 基于 config 秘钥,构建 S3 客户端的认证信息
45 50 *
46   - * @return URI 地址
  51 + * @return S3 客户端的认证信息
47 52 */
48   - private String buildEndpointURL() {
49   - // 如果已经是 http 或者 https,则不进行拼接.主要适配 MinIO
50   - if (HttpUtil.isHttp(config.getEndpoint()) || HttpUtil.isHttps(config.getEndpoint())) {
51   - return config.getEndpoint();
52   - }
53   - return StrUtil.format("https://{}", config.getEndpoint());
  53 + private AWSStaticCredentialsProvider buildCredentials() {
  54 + return new AWSStaticCredentialsProvider(
  55 + new BasicAWSCredentials(config.getAccessKey(), config.getAccessSecret()));
  56 + }
  57 +
  58 + /**
  59 + * 构建 S3 客户端的 Endpoint 配置,包括 region、endpoint
  60 + *
  61 + * @return S3 客户端的 EndpointConfiguration 配置
  62 + */
  63 + private AwsClientBuilder.EndpointConfiguration buildEndpointConfiguration() {
  64 + return new AwsClientBuilder.EndpointConfiguration(config.getEndpoint(),
  65 + null); // 无需设置 region
54 66 }
55 67  
56 68 /**
... ... @@ -67,76 +79,39 @@ public class S3FileClient extends AbstractFileClient&lt;S3FileClientConfig&gt; {
67 79 return StrUtil.format("https://{}.{}", config.getBucket(), config.getEndpoint());
68 80 }
69 81  
70   - /**
71   - * 基于 bucket 构建 region 地区
72   - *
73   - * @return region 地区
74   - */
75   - private String buildRegion() {
76   - // 阿里云必须有 region,否则会报错
77   - if (config.getEndpoint().contains(S3FileClientConfig.ENDPOINT_ALIYUN)) {
78   - return StrUtil.subBefore(config.getEndpoint(), '.', false)
79   - .replaceAll("-internal", "")// 去除内网 Endpoint 的后缀
80   - .replaceAll("https://", "");
81   - }
82   - // 腾讯云必须有 region,否则会报错
83   - if (config.getEndpoint().contains(S3FileClientConfig.ENDPOINT_TENCENT)) {
84   - return StrUtil.subAfter(config.getEndpoint(), "cos.", false)
85   - .replaceAll("." + S3FileClientConfig.ENDPOINT_TENCENT, ""); // 去除 Endpoint
86   - }
87   - return null;
88   - }
89   -
90   - /**
91   - * 开启 VirtualStyle 模式
92   - */
93   - private void enableVirtualStyleEndpoint() {
94   - if (StrUtil.containsAny(config.getEndpoint(),
95   - S3FileClientConfig.ENDPOINT_TENCENT, // 腾讯云 https://cloud.tencent.com/document/product/436/41284
96   - S3FileClientConfig.ENDPOINT_VOLCES)) { // 火山云 https://www.volcengine.com/docs/6349/1288493
97   - client.enableVirtualStyleEndpoint();
98   - }
99   - }
100   -
101 82 @Override
102 83 public String upload(byte[] content, String path, String type) throws Exception {
  84 + // 元数据,主要用于设置文件类型
  85 + ObjectMetadata objectMetadata = new ObjectMetadata();
  86 + objectMetadata.setContentType(type);
  87 + objectMetadata.setContentLength(content.length); // 如果不设置,会有 “ No content length specified for stream data” 警告日志
103 88 // 执行上传
104   - client.putObject(PutObjectArgs.builder()
105   - .bucket(config.getBucket()) // bucket 必须传递
106   - .contentType(type)
107   - .object(path) // 相对路径作为 key
108   - .stream(new ByteArrayInputStream(content), content.length, -1) // 文件内容
109   - .build());
  89 + client.putObject(config.getBucket(),
  90 + path, // 相对路径
  91 + new ByteArrayInputStream(content), // 文件内容
  92 + objectMetadata);
  93 +
110 94 // 拼接返回路径
111 95 return config.getDomain() + "/" + path;
112 96 }
113 97  
114 98 @Override
115 99 public void delete(String path) throws Exception {
116   - client.removeObject(RemoveObjectArgs.builder()
117   - .bucket(config.getBucket()) // bucket 必须传递
118   - .object(path) // 相对路径作为 key
119   - .build());
  100 + client.deleteObject(config.getBucket(), path);
120 101 }
121 102  
122 103 @Override
123 104 public byte[] getContent(String path) throws Exception {
124   - GetObjectResponse response = client.getObject(GetObjectArgs.builder()
125   - .bucket(config.getBucket()) // bucket 必须传递
126   - .object(path) // 相对路径作为 key
127   - .build());
128   - return IoUtil.readBytes(response);
  105 + S3Object tempS3Object = client.getObject(config.getBucket(), path);
  106 + return IoUtil.readBytes(tempS3Object.getObjectContent());
129 107 }
130 108  
131 109 @Override
132 110 public FilePresignedUrlRespDTO getPresignedObjectUrl(String path) throws Exception {
133   - String uploadUrl = client.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
134   - .method(Method.PUT)
135   - .bucket(config.getBucket())
136   - .object(path)
137   - .expiry(10, TimeUnit.MINUTES) // 过期时间(秒数)取值范围:1 秒 ~ 7 天
138   - .build()
139   - );
  111 + // 设定过期时间为 10 分钟。取值范围:1 秒 ~ 7 天
  112 + Date expiration = new Date(System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(10));
  113 + // 生成上传 URL
  114 + String uploadUrl = String.valueOf(client.generatePresignedUrl(config.getBucket(), path, expiration , HttpMethod.PUT));
140 115 return new FilePresignedUrlRespDTO(uploadUrl, config.getDomain() + "/" + path);
141 116 }
142 117  
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClientConfig.java
... ... @@ -28,7 +28,8 @@ public class S3FileClientConfig implements FileClientConfig {
28 28 * 2. 阿里云:https://help.aliyun.com/document_detail/31837.html
29 29 * 3. 腾讯云:https://cloud.tencent.com/document/product/436/6224
30 30 * 4. 七牛云:https://developer.qiniu.com/kodo/4088/s3-access-domainname
31   - * 5. 华为云:https://developer.huaweicloud.com/endpoint?OBS
  31 + * 5. 华为云:https://console.huaweicloud.com/apiexplorer/#/endpoint/OBS
  32 + * 6. 火山云:https://www.volcengine.com/docs/6349/107356
32 33 */
33 34 @NotNull(message = "endpoint 不能为空")
34 35 private String endpoint;
... ... @@ -39,6 +40,7 @@ public class S3FileClientConfig implements FileClientConfig {
39 40 * 3. 腾讯云:https://cloud.tencent.com/document/product/436/11142
40 41 * 4. 七牛云:https://developer.qiniu.com/kodo/8556/set-the-custom-source-domain-name
41 42 * 5. 华为云:https://support.huaweicloud.com/usermanual-obs/obs_03_0032.html
  43 + * 6. 火山云:https://www.volcengine.com/docs/6349/128983
42 44 */
43 45 @URL(message = "domain 必须是 URL 格式")
44 46 private String domain;
... ... @@ -55,6 +57,7 @@ public class S3FileClientConfig implements FileClientConfig {
55 57 * 3. 腾讯云:https://console.cloud.tencent.com/cam/capi
56 58 * 4. 七牛云:https://portal.qiniu.com/user/key
57 59 * 5. 华为云:https://support.huaweicloud.com/qs-obs/obs_qs_0005.html
  60 + * 6. 火山云:https://console.volcengine.com/iam/keymanage/
58 61 */
59 62 @NotNull(message = "accessKey 不能为空")
60 63 private String accessKey;
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/brand/ProductBrandDO.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.product.dal.dataobject.brand;
2 2  
3 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 4 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  5 +import com.baomidou.mybatisplus.annotation.KeySequence;
5 6 import com.baomidou.mybatisplus.annotation.TableId;
6 7 import com.baomidou.mybatisplus.annotation.TableName;
7 8 import lombok.*;
... ... @@ -12,6 +13,7 @@ import lombok.*;
12 13 * @author 芋道源码
13 14 */
14 15 @TableName("product_brand")
  16 +@KeySequence("product_brand_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
15 17 @Data
16 18 @EqualsAndHashCode(callSuper = true)
17 19 @ToString(callSuper = true)
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/category/ProductCategoryDO.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.product.dal.dataobject.category;
2 2  
3 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 4 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  5 +import com.baomidou.mybatisplus.annotation.KeySequence;
5 6 import com.baomidou.mybatisplus.annotation.TableId;
6 7 import com.baomidou.mybatisplus.annotation.TableName;
7 8 import lombok.*;
... ... @@ -12,6 +13,7 @@ import lombok.*;
12 13 * @author 芋道源码
13 14 */
14 15 @TableName("product_category")
  16 +@KeySequence("product_category_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
15 17 @Data
16 18 @EqualsAndHashCode(callSuper = true)
17 19 @ToString(callSuper = true)
... ...
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/point/PointActivityApi.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.api.point;
  2 +
  3 +import cn.iocoder.yudao.module.promotion.api.point.dto.PointValidateJoinRespDTO;
  4 +
  5 +/**
  6 + * 积分商城活动 API 接口
  7 + *
  8 + * @author HUIHUI
  9 + */
  10 +public interface PointActivityApi {
  11 +
  12 + /**
  13 + * 【下单前】校验是否参与积分商城活动
  14 + *
  15 + * 如果校验失败,则抛出业务异常
  16 + *
  17 + * @param activityId 活动编号
  18 + * @param skuId SKU 编号
  19 + * @param count 数量
  20 + * @return 积分商城商品信息
  21 + */
  22 + PointValidateJoinRespDTO validateJoinPointActivity(Long activityId, Long skuId, Integer count);
  23 +
  24 + /**
  25 + * 更新积分商城商品库存(减少)
  26 + *
  27 + * @param id 活动编号
  28 + * @param skuId sku 编号
  29 + * @param count 数量(正数)
  30 + */
  31 + void updatePointStockDecr(Long id, Long skuId, Integer count);
  32 +
  33 + /**
  34 + * 更新积分商城商品库存(增加)
  35 + *
  36 + * @param id 活动编号
  37 + * @param skuId sku 编号
  38 + * @param count 数量(正数)
  39 + */
  40 + void updatePointStockIncr(Long id, Long skuId, Integer count);
  41 +
  42 +}
... ...
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/point/dto/PointValidateJoinRespDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.api.point.dto;
  2 +
  3 +import lombok.Data;
  4 +
  5 +/**
  6 + * 校验参与积分商城 Response DTO
  7 + */
  8 +@Data
  9 +public class PointValidateJoinRespDTO {
  10 +
  11 + /**
  12 + * 可兑换次数
  13 + */
  14 + private Integer count;
  15 + /**
  16 + * 所需兑换积分
  17 + */
  18 + private Integer point;
  19 + /**
  20 + * 所需兑换金额,单位:分
  21 + */
  22 + private Integer price;
  23 +
  24 +}
... ...
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
... ... @@ -50,6 +50,10 @@ public interface ErrorCodeConstants {
50 50 ErrorCode POINT_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_007_002, "积分商城活动已关闭,不能修改");
51 51 ErrorCode POINT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1_013_007_003, "积分商城活动未关闭或未结束,不能删除");
52 52 ErrorCode POINT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_007_004, "积分商城活动已关闭,不能重复关闭");
  53 + ErrorCode POINT_ACTIVITY_JOIN_ACTIVITY_STATUS_CLOSED = new ErrorCode(1_013_007_005, "积分商品兑换失败,原因:积分商城活动已关闭");
  54 + ErrorCode POINT_ACTIVITY_JOIN_ACTIVITY_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1_013_007_006, "积分商品兑换失败,原因:单次限购超出");
  55 + ErrorCode POINT_ACTIVITY_JOIN_ACTIVITY_PRODUCT_NOT_EXISTS = new ErrorCode(1_013_007_007, "积分商品兑换失败,原因:商品不存在");
  56 + ErrorCode POINT_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1_013_007_008, "积分商品兑换失败,原因:积分商品库存不足");
53 57  
54 58 // ========== 秒杀活动 1-013-008-000 ==========
55 59 ErrorCode SECKILL_ACTIVITY_NOT_EXISTS = new ErrorCode(1_013_008_000, "秒杀活动不存在");
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/point/PointActivityApiImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.api.point;
  2 +
  3 +import cn.iocoder.yudao.module.promotion.api.point.dto.PointValidateJoinRespDTO;
  4 +import cn.iocoder.yudao.module.promotion.service.point.PointActivityService;
  5 +import jakarta.annotation.Resource;
  6 +import org.springframework.stereotype.Service;
  7 +import org.springframework.validation.annotation.Validated;
  8 +
  9 +/**
  10 + * 积分商城活动 Api 接口实现类
  11 + *
  12 + * @author HUIHUI
  13 + */
  14 +@Service
  15 +@Validated
  16 +public class PointActivityApiImpl implements PointActivityApi {
  17 +
  18 + @Resource
  19 + private PointActivityService pointActivityService;
  20 +
  21 + @Override
  22 + public PointValidateJoinRespDTO validateJoinPointActivity(Long activityId, Long skuId, Integer count) {
  23 + return pointActivityService.validateJoinPointActivity(activityId, skuId, count);
  24 + }
  25 +
  26 + @Override
  27 + public void updatePointStockDecr(Long id, Long skuId, Integer count) {
  28 + pointActivityService.updatePointStockDecr(id, skuId, count);
  29 + }
  30 +
  31 + @Override
  32 + public void updatePointStockIncr(Long id, Long skuId, Integer count) {
  33 + pointActivityService.updatePointStockIncr(id, skuId, count);
  34 + }
  35 +
  36 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityBaseVO.java
... ... @@ -63,11 +63,11 @@ public class DiscountActivityBaseVO {
63 63 @Min(value = 0, message = "优惠金额需要大于等于 0")
64 64 private Integer discountPrice;
65 65  
66   - @AssertTrue(message = "折扣百分比需要大于等于 1,小于等于 99")
  66 + @AssertTrue(message = "折扣百分比需要大于等于 0.01%,小于等于 99.99%")
67 67 @JsonIgnore
68 68 public boolean isDiscountPercentValid() {
69 69 return ObjectUtil.notEqual(discountType, PromotionDiscountTypeEnum.PERCENT.getType())
70   - || (discountPercent != null && discountPercent >= 1 && discountPercent<= 99);
  70 + || (discountPercent != null && discountPercent >= 1 && discountPercent <= 9999);
71 71 }
72 72  
73 73 @AssertTrue(message = "优惠金额不能为空")
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/point/AppPointActivityController.java
... ... @@ -76,8 +76,11 @@ public class AppPointActivityController {
76 76  
77 77 // 2. 拼接数据
78 78 List<PointProductDO> products = pointActivityService.getPointProductListByActivityIds(Collections.singletonList(id));
79   - AppPointActivityDetailRespVO respVO = BeanUtils.toBean(activity, AppPointActivityDetailRespVO.class);
80   - respVO.setProducts(BeanUtils.toBean(products, AppPointActivityDetailRespVO.Product.class));
  79 + PointProductDO minProduct = getMinObject(products, PointProductDO::getPoint);
  80 + assert minProduct != null;
  81 + AppPointActivityDetailRespVO respVO = BeanUtils.toBean(activity, AppPointActivityDetailRespVO.class)
  82 + .setProducts(BeanUtils.toBean(products, AppPointActivityDetailRespVO.Product.class))
  83 + .setPoint(minProduct.getPoint()).setPrice(minProduct.getPrice());
81 84 return success(respVO);
82 85 }
83 86  
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/point/vo/AppPointActivityDetailRespVO.java
... ... @@ -30,6 +30,14 @@ public class AppPointActivityDetailRespVO {
30 30 @Schema(description = "商品信息数组", requiredMode = Schema.RequiredMode.REQUIRED)
31 31 private List<Product> products;
32 32  
  33 + //======================= 显示所需兑换积分最少的 SKU 信息 =======================
  34 +
  35 + @Schema(description = "兑换积分", requiredMode = Schema.RequiredMode.REQUIRED)
  36 + private Integer point;
  37 +
  38 + @Schema(description = "兑换金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "15860")
  39 + private Integer price;
  40 +
33 41 @Schema(description = "商品信息")
34 42 @Data
35 43 public static class Product {
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/banner/BannerDO.java
... ... @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.promotion.dal.dataobject.banner;
3 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 4 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
5 5 import cn.iocoder.yudao.module.promotion.enums.banner.BannerPositionEnum;
  6 +import com.baomidou.mybatisplus.annotation.KeySequence;
6 7 import com.baomidou.mybatisplus.annotation.TableName;
7 8 import lombok.*;
8 9  
... ... @@ -12,6 +13,7 @@ import lombok.*;
12 13 * @author xia
13 14 */
14 15 @TableName("promotion_banner")
  16 +@KeySequence("promotion_banner_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
15 17 @Data
16 18 @EqualsAndHashCode(callSuper = true)
17 19 @ToString(callSuper = true)
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponTemplateDO.java
... ... @@ -30,6 +30,11 @@ import java.util.List;
30 30 @EqualsAndHashCode(callSuper = true)
31 31 public class CouponTemplateDO extends BaseDO {
32 32  
  33 + /**
  34 + * 不限制领取数量
  35 + */
  36 + public static final Integer TIME_LIMIT_COUNT_MAX = -1;
  37 +
33 38 // ========== 基本信息 BEGIN ==========
34 39 /**
35 40 * 模板编号,自增唯一
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/point/PointActivityMapper.java
1 1 package cn.iocoder.yudao.module.promotion.dal.mysql.point;
2 2  
  3 +import cn.hutool.core.lang.Assert;
3 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 5 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 6 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
6 7 import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivityPageReqVO;
7 8 import cn.iocoder.yudao.module.promotion.dal.dataobject.point.PointActivityDO;
  9 +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
8 10 import org.apache.ibatis.annotations.Mapper;
9 11  
10 12 /**
... ... @@ -25,4 +27,33 @@ public interface PointActivityMapper extends BaseMapperX&lt;PointActivityDO&gt; {
25 27 .orderByDesc(PointActivityDO::getId));
26 28 }
27 29  
  30 + /**
  31 + * 更新活动库存(减少)
  32 + *
  33 + * @param id 活动编号
  34 + * @param count 扣减的库存数量(正数)
  35 + * @return 影响的行数
  36 + */
  37 + default int updateStockDecr(Long id, int count) {
  38 + Assert.isTrue(count > 0);
  39 + return update(null, new LambdaUpdateWrapper<PointActivityDO>()
  40 + .eq(PointActivityDO::getId, id)
  41 + .ge(PointActivityDO::getStock, count)
  42 + .setSql("stock = stock - " + count));
  43 + }
  44 +
  45 + /**
  46 + * 更新活动库存(增加)
  47 + *
  48 + * @param id 活动编号
  49 + * @param count 增加的库存数量(正数)
  50 + * @return 影响的行数
  51 + */
  52 + default int updateStockIncr(Long id, int count) {
  53 + Assert.isTrue(count > 0);
  54 + return update(null, new LambdaUpdateWrapper<PointActivityDO>()
  55 + .eq(PointActivityDO::getId, id)
  56 + .setSql("stock = stock + " + count));
  57 + }
  58 +
28 59 }
29 60 \ No newline at end of file
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/point/PointProductMapper.java
1 1 package cn.iocoder.yudao.module.promotion.dal.mysql.point;
2 2  
  3 +import cn.hutool.core.lang.Assert;
3 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
4 5 import cn.iocoder.yudao.module.promotion.dal.dataobject.point.PointProductDO;
5 6 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
... ... @@ -29,4 +30,37 @@ public interface PointProductMapper extends BaseMapperX&lt;PointProductDO&gt; {
29 30 .eq(PointProductDO::getActivityId, pointProductDO.getActivityId()));
30 31 }
31 32  
  33 + default PointProductDO selectListByActivityIdAndSkuId(Long activityId, Long skuId) {
  34 + return selectOne(PointProductDO::getActivityId, activityId,
  35 + PointProductDO::getSkuId, skuId);
  36 + }
  37 +
  38 + /**
  39 + * 更新活动库存(减少)
  40 + *
  41 + * @param id 活动编号
  42 + * @param count 扣减的库存数量(减少库存)
  43 + * @return 影响的行数
  44 + */
  45 + default int updateStockDecr(Long id, int count) {
  46 + Assert.isTrue(count > 0);
  47 + return update(null, new LambdaUpdateWrapper<PointProductDO>()
  48 + .eq(PointProductDO::getId, id)
  49 + .ge(PointProductDO::getStock, count)
  50 + .setSql("stock = stock - " + count));
  51 + }
  52 +
  53 + /**
  54 + * 更新活动库存(增加)
  55 + *
  56 + * @param id 活动编号
  57 + * @param count 需要增加的库存(增加库存)
  58 + * @return 影响的行数
  59 + */
  60 + default int updateStockIncr(Long id, int count) {
  61 + Assert.isTrue(count > 0);
  62 + return update(null, new LambdaUpdateWrapper<PointProductDO>()
  63 + .eq(PointProductDO::getId, id)
  64 + .setSql("stock = stock + " + count));
  65 + }
32 66 }
33 67 \ No newline at end of file
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java
... ... @@ -131,7 +131,7 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
131 131 throw exception(COMBINATION_JOIN_ACTIVITY_PRODUCT_NOT_EXISTS);
132 132 }
133 133 // 4.3 校验库存是否充足
134   - if (count > sku.getStock()) {
  134 + if (count >= sku.getStock()) {
135 135 throw exception(COMBINATION_ACTIVITY_UPDATE_STOCK_FAIL);
136 136 }
137 137  
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java
... ... @@ -269,7 +269,8 @@ public class CouponServiceImpl implements CouponService {
269 269 throw exception(COUPON_TEMPLATE_NOT_EXISTS);
270 270 }
271 271 // 校验剩余数量
272   - if (couponTemplate.getTakeCount() + userIds.size() > couponTemplate.getTotalCount()) {
  272 + if (ObjUtil.notEqual(couponTemplate.getTakeLimitCount(), CouponTemplateDO.TIME_LIMIT_COUNT_MAX) // 非不限制
  273 + && couponTemplate.getTakeCount() + userIds.size() > couponTemplate.getTotalCount()) {
273 274 throw exception(COUPON_TEMPLATE_NOT_ENOUGH);
274 275 }
275 276 // 校验"固定日期"的有效期类型是否过期
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java
1 1 package cn.iocoder.yudao.module.promotion.service.coupon;
2 2  
  3 +import cn.hutool.core.util.ObjUtil;
3 4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 6 import cn.iocoder.yudao.module.product.api.category.ProductCategoryApi;
... ... @@ -59,7 +60,7 @@ public class CouponTemplateServiceImpl implements CouponTemplateService {
59 60 CouponTemplateDO couponTemplate = validateCouponTemplateExists(updateReqVO.getId());
60 61 // 校验发放数量不能过小(仅在 CouponTakeTypeEnum.USER 用户领取时)
61 62 if (CouponTakeTypeEnum.isUser(couponTemplate.getTakeType())
62   - && updateReqVO.getTotalCount() > 0 // 大于 0 的原因,是因为 -1 不限制
  63 + && ObjUtil.notEqual(couponTemplate.getTakeLimitCount(), CouponTemplateDO.TIME_LIMIT_COUNT_MAX) // 非不限制
63 64 && updateReqVO.getTotalCount() < couponTemplate.getTakeCount()) {
64 65 throw exception(COUPON_TEMPLATE_TOTAL_COUNT_TOO_SMALL, couponTemplate.getTakeCount());
65 66 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/point/PointActivityService.java
1 1 package cn.iocoder.yudao.module.promotion.service.point;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.promotion.api.point.dto.PointValidateJoinRespDTO;
4 5 import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivityPageReqVO;
5 6 import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivitySaveReqVO;
6 7 import cn.iocoder.yudao.module.promotion.dal.dataobject.point.PointActivityDO;
... ... @@ -33,6 +34,24 @@ public interface PointActivityService {
33 34 void updatePointActivity(@Valid PointActivitySaveReqVO updateReqVO);
34 35  
35 36 /**
  37 + * 更新积分商城商品库存(减少)
  38 + *
  39 + * @param id 活动编号
  40 + * @param skuId sku 编号
  41 + * @param count 数量(正数)
  42 + */
  43 + void updatePointStockDecr(Long id, Long skuId, Integer count);
  44 +
  45 + /**
  46 + * 更新积分商城商品库存(增加)
  47 + *
  48 + * @param id 活动编号
  49 + * @param skuId sku 编号
  50 + * @param count 数量(正数)
  51 + */
  52 + void updatePointStockIncr(Long id, Long skuId, Integer count);
  53 +
  54 + /**
36 55 * 关闭积分商城活动
37 56 *
38 57 * @param id 编号
... ... @@ -78,4 +97,16 @@ public interface PointActivityService {
78 97 */
79 98 List<PointProductDO> getPointProductListByActivityIds(Collection<Long> activityIds);
80 99  
  100 + /**
  101 + * 【下单前】校验是否参与积分商城活动
  102 + *
  103 + * 如果校验失败,则抛出业务异常
  104 + *
  105 + * @param activityId 活动编号
  106 + * @param skuId SKU 编号
  107 + * @param count 数量
  108 + * @return 积分商城商品信息
  109 + */
  110 + PointValidateJoinRespDTO validateJoinPointActivity(Long activityId, Long skuId, Integer count);
  111 +
81 112 }
82 113 \ No newline at end of file
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/point/PointActivityServiceImpl.java
... ... @@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
8 8 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
9 9 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
10 10 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
  11 +import cn.iocoder.yudao.module.promotion.api.point.dto.PointValidateJoinRespDTO;
11 12 import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivityPageReqVO;
12 13 import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.activity.PointActivitySaveReqVO;
13 14 import cn.iocoder.yudao.module.promotion.controller.admin.point.vo.product.PointProductSaveReqVO;
... ... @@ -104,6 +105,43 @@ public class PointActivityServiceImpl implements PointActivityService {
104 105  
105 106 @Override
106 107 @Transactional(rollbackFor = Exception.class)
  108 + public void updatePointStockDecr(Long id, Long skuId, Integer count) {
  109 + // 1.1 校验活动库存是否充足
  110 + PointActivityDO activity = validatePointActivityExists(id);
  111 + if (count > activity.getStock()) {
  112 + throw exception(POINT_ACTIVITY_UPDATE_STOCK_FAIL);
  113 + }
  114 + // 1.2 校验商品库存是否充足
  115 + PointProductDO product = pointProductMapper.selectListByActivityIdAndSkuId(id, skuId);
  116 + if (product == null || count > product.getStock()) {
  117 + throw exception(POINT_ACTIVITY_UPDATE_STOCK_FAIL);
  118 + }
  119 +
  120 + // 2.1 更新活动商品库存
  121 + int updateCount = pointProductMapper.updateStockDecr(product.getId(), count);
  122 + if (updateCount == 0) {
  123 + throw exception(POINT_ACTIVITY_UPDATE_STOCK_FAIL);
  124 + }
  125 +
  126 + // 2.2 更新活动库存
  127 + updateCount = pointActivityMapper.updateStockDecr(id, count);
  128 + if (updateCount == 0) {
  129 + throw exception(POINT_ACTIVITY_UPDATE_STOCK_FAIL);
  130 + }
  131 + }
  132 +
  133 + @Override
  134 + @Transactional(rollbackFor = Exception.class)
  135 + public void updatePointStockIncr(Long id, Long skuId, Integer count) {
  136 + PointProductDO product = pointProductMapper.selectListByActivityIdAndSkuId(id, skuId);
  137 + // 更新活动商品库存
  138 + pointProductMapper.updateStockIncr(product.getId(), count);
  139 + // 更新活动库存
  140 + pointActivityMapper.updateStockIncr(id, count);
  141 + }
  142 +
  143 + @Override
  144 + @Transactional(rollbackFor = Exception.class)
107 145 public void closePointActivity(Long id) {
108 146 // 校验存在
109 147 PointActivityDO pointActivity = validatePointActivityExists(id);
... ... @@ -244,4 +282,28 @@ public class PointActivityServiceImpl implements PointActivityService {
244 282 return pointProductMapper.selectListByActivityId(activityIds);
245 283 }
246 284  
  285 + @Override
  286 + public PointValidateJoinRespDTO validateJoinPointActivity(Long activityId, Long skuId, Integer count) {
  287 + // 1. 校验积分商城活动是否存在
  288 + PointActivityDO activity = validatePointActivityExists(activityId);
  289 + if (CommonStatusEnum.isDisable(activity.getStatus())) {
  290 + throw exception(POINT_ACTIVITY_JOIN_ACTIVITY_STATUS_CLOSED);
  291 + }
  292 +
  293 + // 2.1 校验积分商城商品是否存在
  294 + PointProductDO product = pointProductMapper.selectListByActivityIdAndSkuId(activityId, skuId);
  295 + if (product == null) {
  296 + throw exception(POINT_ACTIVITY_JOIN_ACTIVITY_PRODUCT_NOT_EXISTS);
  297 + }
  298 + // 2.2 超过单次购买限制
  299 + if (count > product.getCount()) {
  300 + throw exception(POINT_ACTIVITY_JOIN_ACTIVITY_SINGLE_LIMIT_COUNT_EXCEED);
  301 + }
  302 + // 2.2 校验库存是否充足
  303 + if (count >= product.getStock()) {
  304 + throw exception(POINT_ACTIVITY_UPDATE_STOCK_FAIL);
  305 + }
  306 + return BeanUtils.toBean(product, PointValidateJoinRespDTO.class);
  307 + }
  308 +
247 309 }
248 310 \ No newline at end of file
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java
... ... @@ -160,7 +160,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
160 160 public void updateSeckillStockDecr(Long id, Long skuId, Integer count) {
161 161 // 1.1 校验活动库存是否充足
162 162 SeckillActivityDO seckillActivity = validateSeckillActivityExists(id);
163   - if (count > seckillActivity.getTotalStock()) {
  163 + if (count > seckillActivity.getStock()) {
164 164 throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
165 165 }
166 166 // 1.2 校验商品库存是否充足
... ... @@ -317,7 +317,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
317 317 throw exception(SECKILL_JOIN_ACTIVITY_PRODUCT_NOT_EXISTS);
318 318 }
319 319 // 2.2 校验库存是否充足
320   - if (count > product.getStock()) {
  320 + if (count >= product.getStock()) {
321 321 throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
322 322 }
323 323 return SeckillActivityConvert.INSTANCE.convert02(activity, product);
... ...
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java
... ... @@ -58,11 +58,12 @@ public interface ErrorCodeConstants {
58 58  
59 59 // ========== Price 相关 1-011-003-000 ============
60 60 ErrorCode PRICE_CALCULATE_PAY_PRICE_ILLEGAL = new ErrorCode(1_011_003_000, "支付价格计算异常,原因:价格小于等于 0");
61   - ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND = new ErrorCode(1_011_003_002, "计算快递运费异常,找不到对应的运费模板");
62   - ErrorCode PRICE_CALCULATE_COUPON_NOT_MATCH_NORMAL_ORDER = new ErrorCode(1_011_003_004, "参与秒杀、拼团、砍价的营销商品,无法使用优惠劵");
63   - ErrorCode PRICE_CALCULATE_SECKILL_TOTAL_LIMIT_COUNT = new ErrorCode(1_011_003_005, "参与秒杀的商品,超过了秒杀总限购数量");
64   - ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TYPE_ILLEGAL = new ErrorCode(1_011_003_006, "计算快递运费异常,配送方式不匹配");
65   - ErrorCode PRICE_CALCULATE_COUPON_CAN_NOT_USE = new ErrorCode(1_011_003_007, "该优惠劵无法使用,原因:{}」");
  61 + ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND = new ErrorCode(1_011_003_001, "计算快递运费异常,找不到对应的运费模板");
  62 + ErrorCode PRICE_CALCULATE_COUPON_NOT_MATCH_NORMAL_ORDER = new ErrorCode(1_011_003_002, "参与秒杀、拼团、砍价的营销商品,无法使用优惠劵");
  63 + ErrorCode PRICE_CALCULATE_SECKILL_TOTAL_LIMIT_COUNT = new ErrorCode(1_011_003_003, "参与秒杀的商品,超过了秒杀总限购数量");
  64 + ErrorCode PRICE_CALCULATE_POINT_TOTAL_LIMIT_COUNT = new ErrorCode(1_011_003_004, "参与积分活动的商品,超过了积分活动商品总限购数量");
  65 + ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TYPE_ILLEGAL = new ErrorCode(1_011_003_005, "计算快递运费异常,配送方式不匹配");
  66 + ErrorCode PRICE_CALCULATE_COUPON_CAN_NOT_USE = new ErrorCode(1_011_003_006, "该优惠劵无法使用,原因:{}」");
66 67  
67 68 // ========== 物流 Express 模块 1-011-004-000 ==========
68 69 ErrorCode EXPRESS_NOT_EXISTS = new ErrorCode(1_011_004_000, "快递公司不存在");
... ...
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderTypeEnum.java
... ... @@ -20,6 +20,7 @@ public enum TradeOrderTypeEnum implements IntArrayValuable {
20 20 SECKILL(1, "秒杀订单"),
21 21 BARGAIN(2, "砍价订单"),
22 22 COMBINATION(3, "拼团订单"),
  23 + POINT(4, "积分商城"),
23 24 ;
24 25  
25 26 public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeOrderTypeEnum::getType).toArray();
... ... @@ -54,4 +55,8 @@ public enum TradeOrderTypeEnum implements IntArrayValuable {
54 55 return ObjectUtil.equal(type, COMBINATION.getType());
55 56 }
56 57  
  58 + public static boolean isPoint(Integer type) {
  59 + return ObjectUtil.equal(type, POINT.getType());
  60 + }
  61 +
57 62 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java
... ... @@ -80,6 +80,7 @@ public class AppTradeOrderController {
80 80  
81 81 @PostMapping("/update-paid")
82 82 @Operation(summary = "更新订单为已支付") // 由 pay-module 支付服务,进行回调,可见 PayNotifyJob
  83 + @PermitAll
83 84 public CommonResult<Boolean> updateOrderPaid(@RequestBody PayOrderNotifyReqDTO notifyReqDTO) {
84 85 tradeOrderUpdateService.updateOrderPaid(Long.valueOf(notifyReqDTO.getMerchantOrderId()),
85 86 notifyReqDTO.getPayOrderId());
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementReqVO.java
... ... @@ -6,13 +6,13 @@ import cn.iocoder.yudao.framework.common.validation.Mobile;
6 6 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
7 7 import com.fasterxml.jackson.annotation.JsonIgnore;
8 8 import io.swagger.v3.oas.annotations.media.Schema;
9   -import lombok.Data;
10   -
11 9 import jakarta.validation.Valid;
12 10 import jakarta.validation.constraints.AssertTrue;
13 11 import jakarta.validation.constraints.Min;
14 12 import jakarta.validation.constraints.NotEmpty;
15 13 import jakarta.validation.constraints.NotNull;
  14 +import lombok.Data;
  15 +
16 16 import java.util.List;
17 17  
18 18 @Schema(description = "用户 App - 交易订单结算 Request VO")
... ... @@ -62,6 +62,10 @@ public class AppTradeOrderSettlementReqVO {
62 62 @Schema(description = "砍价记录编号", example = "123")
63 63 private Long bargainRecordId;
64 64  
  65 + // ========== 积分商城活动相关字段 ==========
  66 + @Schema(description = "积分商城活动编号", example = "123")
  67 + private Long pointActivityId;
  68 +
65 69 @AssertTrue(message = "活动商品每次只能购买一种规格")
66 70 @JsonIgnore
67 71 public boolean isValidActivityItems() {
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
... ... @@ -219,7 +219,8 @@ public interface TradeOrderConvert {
219 219 .setSeckillActivityId(settlementReqVO.getSeckillActivityId())
220 220 .setBargainRecordId(settlementReqVO.getBargainRecordId())
221 221 .setCombinationActivityId(settlementReqVO.getCombinationActivityId())
222   - .setCombinationHeadId(settlementReqVO.getCombinationHeadId());
  222 + .setCombinationHeadId(settlementReqVO.getCombinationHeadId())
  223 + .setPointActivityId(settlementReqVO.getPointActivityId());
223 224 // 商品项的构建
224 225 Map<Long, CartDO> cartMap = convertMap(cartList, CartDO::getId);
225 226 for (AppTradeOrderSettlementReqVO.Item item : settlementReqVO.getItems()) {
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/AfterSaleDO.java
... ... @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
6 6 import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleStatusEnum;
7 7 import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleTypeEnum;
8 8 import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleWayEnum;
  9 +import com.baomidou.mybatisplus.annotation.KeySequence;
9 10 import com.baomidou.mybatisplus.annotation.TableField;
10 11 import com.baomidou.mybatisplus.annotation.TableName;
11 12 import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
... ... @@ -22,6 +23,7 @@ import java.util.List;
22 23 * @author 芋道源码
23 24 */
24 25 @TableName(value = "trade_after_sale", autoResultMap = true)
  26 +@KeySequence("trade_after_sale_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
25 27 @Data
26 28 @EqualsAndHashCode(callSuper = true)
27 29 @Accessors(chain = true)
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/CartDO.java
1 1 package cn.iocoder.yudao.module.trade.dal.dataobject.cart;
2 2  
3 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import com.baomidou.mybatisplus.annotation.KeySequence;
4 5 import com.baomidou.mybatisplus.annotation.TableName;
5 6 import lombok.Data;
6 7 import lombok.EqualsAndHashCode;
... ... @@ -14,6 +15,7 @@ import lombok.experimental.Accessors;
14 15 * @author 芋道源码
15 16 */
16 17 @TableName("trade_cart")
  18 +@KeySequence("trade_cart_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
17 19 @Data
18 20 @EqualsAndHashCode(callSuper = true)
19 21 @Accessors(chain = true)
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java
... ... @@ -353,4 +353,11 @@ public class TradeOrderDO extends BaseDO {
353 353 */
354 354 private Long combinationRecordId;
355 355  
  356 + /**
  357 + * 积分商城活动的编号
  358 + *
  359 + * 关联 PointActivityDO 的 id 字段
  360 + */
  361 + private Long pointActivityId;
  362 +
356 363 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java
... ... @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
4 4 import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleDO;
5 5 import cn.iocoder.yudao.module.trade.dal.dataobject.cart.CartDO;
6 6 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum;
  7 +import com.baomidou.mybatisplus.annotation.KeySequence;
7 8 import com.baomidou.mybatisplus.annotation.TableField;
8 9 import com.baomidou.mybatisplus.annotation.TableName;
9 10 import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
... ... @@ -20,6 +21,7 @@ import java.util.List;
20 21 * @author 芋道源码
21 22 */
22 23 @TableName(value = "trade_order_item", autoResultMap = true)
  24 +@KeySequence("trade_order_item_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
23 25 @Data
24 26 @Accessors(chain = true)
25 27 @EqualsAndHashCode(callSuper = true)
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/AfterSaleServiceImpl.java
... ... @@ -399,7 +399,7 @@ public class AfterSaleServiceImpl implements AfterSaleService {
399 399 @AfterSaleLog(operateType = AfterSaleOperateTypeEnum.MEMBER_CANCEL)
400 400 public void cancelAfterSale(Long userId, Long id) {
401 401 // 校验售后单的状态,并状态待退款
402   - AfterSaleDO afterSale = tradeAfterSaleMapper.selectById(id);
  402 + AfterSaleDO afterSale = tradeAfterSaleMapper.selectByIdAndUserId(id, userId);
403 403 if (afterSale == null) {
404 404 throw exception(AFTER_SALE_NOT_FOUND);
405 405 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryService.java
... ... @@ -42,9 +42,9 @@ public interface TradeOrderQueryService {
42 42 /**
43 43 * 获得指定用户,指定活动,指定状态的交易订单
44 44 *
45   - * @param userId 用户编号
  45 + * @param userId 用户编号
46 46 * @param combinationActivityId 活动编号
47   - * @param status 订单状态
  47 + * @param status 订单状态
48 48 * @return 交易订单
49 49 */
50 50 TradeOrderDO getOrderByUserIdAndStatusAndCombination(Long userId, Long combinationActivityId, Integer status);
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
... ... @@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.date.LocalDateTimeUtil;
5 5 import cn.hutool.core.lang.Assert;
6 6 import cn.hutool.core.map.MapUtil;
  7 +import cn.hutool.core.net.NetUtil;
7 8 import cn.hutool.core.util.ObjUtil;
8 9 import cn.hutool.core.util.ObjectUtil;
9 10 import cn.hutool.core.util.RandomUtil;
... ... @@ -245,7 +246,10 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
245 246 }
246 247  
247 248 // 3. 生成预支付
248   - createPayOrder(order, orderItems);
  249 + // 特殊情况:积分兑换时,可能支付金额为零
  250 + if (order.getPayPrice() > 0) {
  251 + createPayOrder(order, orderItems);
  252 + }
249 253  
250 254 // 4. 插入订单日志
251 255 TradeOrderLogUtils.setOrderInfo(order.getId(), null, order.getStatus());
... ... @@ -885,8 +889,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
885 889 if (!order.getPayStatus()) {
886 890 throw exception(ORDER_CANCEL_PAID_FAIL, "已支付");
887 891 }
888   - // 1.3 校验订单是否已退款
889   - if (ObjUtil.equal(TradeOrderRefundStatusEnum.NONE.getStatus(), order.getRefundStatus())) {
  892 + // 1.3 校验订单是否未退款
  893 + if (ObjUtil.notEqual(TradeOrderRefundStatusEnum.NONE.getStatus(), order.getRefundStatus())) {
890 894 throw exception(ORDER_CANCEL_PAID_FAIL, "未退款");
891 895 }
892 896  
... ... @@ -894,7 +898,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
894 898 cancelOrder0(order, TradeOrderCancelTypeEnum.COMBINATION_CLOSE);
895 899 // 2.2 创建退款单
896 900 payRefundApi.createRefund(new PayRefundCreateReqDTO()
897   - .setAppKey(tradeOrderProperties.getPayAppKey()).setUserIp(getClientIP()) // 支付应用
  901 + .setAppKey(tradeOrderProperties.getPayAppKey()) // 支付应用
  902 + .setUserIp(NetUtil.getLocalhostStr()) // 使用本机 IP,因为是服务器发起退款的
898 903 .setMerchantOrderId(String.valueOf(order.getId())) // 支付单号
899 904 .setMerchantRefundId(String.valueOf(order.getId()))
900 905 .setReason(TradeOrderCancelTypeEnum.COMBINATION_CLOSE.getName()).setPrice(order.getPayPrice())); // 价格信息
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradePointOrderHandler.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.order.handler;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.lang.Assert;
  5 +import cn.iocoder.yudao.module.promotion.api.point.PointActivityApi;
  6 +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
  7 +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
  8 +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
  9 +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
  10 +import jakarta.annotation.Resource;
  11 +import org.springframework.stereotype.Component;
  12 +
  13 +import java.util.List;
  14 +import java.util.Objects;
  15 +
  16 +/**
  17 + * 积分商城活动订单的 {@link TradeOrderHandler} 实现类
  18 + *
  19 + * @author HUIHUI
  20 + */
  21 +@Component
  22 +public class TradePointOrderHandler implements TradeOrderHandler {
  23 +
  24 + @Resource
  25 + private PointActivityApi pointActivityApi;
  26 +
  27 + @Override
  28 + public void beforeOrderCreate(TradeOrderDO order, List<TradeOrderItemDO> orderItems) {
  29 + if (!TradeOrderTypeEnum.isPoint(order.getType())) {
  30 + return;
  31 + }
  32 + // 明确校验一下
  33 + Assert.isTrue(orderItems.size() == 1, "积分商城活动兑换商品兑换时,只允许选择一个商品");
  34 +
  35 + // 扣减积分商城活动的库存
  36 + pointActivityApi.updatePointStockDecr(order.getPointActivityId(),
  37 + orderItems.get(0).getSkuId(), orderItems.get(0).getCount());
  38 +
  39 + // 如果支付金额为 0,则直接设置为已支付
  40 + if (Objects.equals(order.getPayPrice(), 0)) {
  41 + order.setPayStatus(true).setStatus(TradeOrderStatusEnum.UNDELIVERED.getStatus());
  42 + }
  43 + }
  44 +
  45 + @Override
  46 + public void afterCancelOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems) {
  47 + if (!TradeOrderTypeEnum.isPoint(order.getType())) {
  48 + return;
  49 + }
  50 + // 明确校验一下
  51 + Assert.isTrue(orderItems.size() == 1, "积分商城活动兑换商品兑换时,只允许选择一个商品");
  52 +
  53 + // 售后的订单项,已经在 afterCancelOrderItem 回滚库存,所以这里不需要重复回滚
  54 + orderItems = filterOrderItemListByNoneAfterSale(orderItems);
  55 + if (CollUtil.isEmpty(orderItems)) {
  56 + return;
  57 + }
  58 + afterCancelOrderItem(order, orderItems.get(0));
  59 + }
  60 +
  61 + @Override
  62 + public void afterCancelOrderItem(TradeOrderDO order, TradeOrderItemDO orderItem) {
  63 + if (!TradeOrderTypeEnum.isPoint(order.getType())) {
  64 + return;
  65 + }
  66 + // 恢复积分商城活动的库存
  67 + pointActivityApi.updatePointStockIncr(order.getPointActivityId(),
  68 + orderItem.getSkuId(), orderItem.getCount());
  69 + }
  70 +
  71 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImpl.java
... ... @@ -69,7 +69,8 @@ public class TradePriceServiceImpl implements TradePriceService {
69 69 .buildCalculateResp(calculateReqBO, spuList, skuList);
70 70 priceCalculators.forEach(calculator -> calculator.calculate(calculateReqBO, calculateRespBO));
71 71 // 2.2 如果最终支付金额小于等于 0,则抛出业务异常
72   - if (calculateRespBO.getPrice().getPayPrice() <= 0) {
  72 + if (calculateReqBO.getPointActivityId() == null // 积分订单,允许支付金额为 0
  73 + && calculateRespBO.getPrice().getPayPrice() <= 0) {
73 74 log.error("[calculatePrice][价格计算不正确,请求 calculateReqDTO({}),结果 priceCalculate({})]",
74 75 calculateReqBO, calculateRespBO);
75 76 throw exception(PRICE_CALCULATE_PAY_PRICE_ILLEGAL);
... ... @@ -121,7 +122,7 @@ public class TradePriceServiceImpl implements TradePriceService {
121 122 List<ProductSkuRespDTO> skuList = spuIdAndSkuListMap.get(spuId);
122 123 List<AppTradeProductSettlementRespVO.Sku> skuVOList = convertList(skuList, sku -> {
123 124 AppTradeProductSettlementRespVO.Sku skuVO = new AppTradeProductSettlementRespVO.Sku()
124   - .setId(sku.getId()).setPromotionPrice(sku.getPrice());
  125 + .setId(sku.getId());
125 126 TradePriceCalculateRespBO.OrderItem orderItem = new TradePriceCalculateRespBO.OrderItem()
126 127 .setPayPrice(sku.getPrice()).setCount(1);
127 128 // 计算限时折扣的优惠价格
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateReqBO.java
1 1 package cn.iocoder.yudao.module.trade.service.price.bo;
2 2  
3 3 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
4   -import lombok.Data;
5   -
6 4 import jakarta.validation.Valid;
7 5 import jakarta.validation.constraints.Min;
8 6 import jakarta.validation.constraints.NotNull;
  7 +import lombok.Data;
  8 +
9 9 import java.util.List;
10 10  
11 11 /**
... ... @@ -84,6 +84,12 @@ public class TradePriceCalculateReqBO {
84 84 */
85 85 private Long bargainRecordId;
86 86  
  87 + // ========== 积分商城活动相关字段 ==========
  88 + /**
  89 + * 积分商城活动编号
  90 + */
  91 + private Long pointActivityId;
  92 +
87 93 /**
88 94 * 商品 SKU
89 95 */
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointActivityPriceCalculator.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.service.price.calculator;
  2 +
  3 +import cn.hutool.core.lang.Assert;
  4 +import cn.hutool.core.util.ObjectUtil;
  5 +import cn.hutool.core.util.StrUtil;
  6 +import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
  7 +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
  8 +import cn.iocoder.yudao.module.promotion.api.point.PointActivityApi;
  9 +import cn.iocoder.yudao.module.promotion.api.point.dto.PointValidateJoinRespDTO;
  10 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum;
  11 +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
  12 +import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
  13 +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
  14 +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
  15 +import jakarta.annotation.Resource;
  16 +import lombok.extern.slf4j.Slf4j;
  17 +import org.springframework.core.annotation.Order;
  18 +import org.springframework.stereotype.Component;
  19 +
  20 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  21 +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PRICE_CALCULATE_POINT_TOTAL_LIMIT_COUNT;
  22 +
  23 +/**
  24 + * 积分商城的 {@link TradePriceCalculator} 实现类
  25 + *
  26 + * @author owen
  27 + */
  28 +@Component
  29 +@Order(TradePriceCalculator.ORDER_POINT_ACTIVITY)
  30 +@Slf4j
  31 +public class TradePointActivityPriceCalculator implements TradePriceCalculator {
  32 +
  33 + @Resource
  34 + private PointActivityApi pointActivityApi;
  35 + @Resource
  36 + private MemberUserApi memberUserApi;
  37 +
  38 + @Resource
  39 + private TradeOrderQueryService tradeOrderQueryService;
  40 +
  41 + @Override
  42 + public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
  43 + // 1.1 判断订单类型是否为积分商城活动
  44 + if (ObjectUtil.notEqual(result.getType(), TradeOrderTypeEnum.POINT.getType())) {
  45 + return;
  46 + }
  47 + // 1.2 初始化积分
  48 + MemberUserRespDTO user = memberUserApi.getUser(param.getUserId());
  49 + result.setTotalPoint(user.getPoint()).setUsePoint(0);
  50 +
  51 + // 1.3 校验用户积分余额
  52 + if (user.getPoint() == null || user.getPoint() <= 0) {
  53 + return;
  54 + }
  55 +
  56 + Assert.isTrue(param.getItems().size() == 1, "积分商城兑换商品时,只允许选择一个商品");
  57 + // 2. 校验是否可以参与积分商城活动
  58 + TradePriceCalculateRespBO.OrderItem orderItem = result.getItems().get(0);
  59 + PointValidateJoinRespDTO activity = validateJoinSeckill(
  60 + param.getUserId(), param.getPointActivityId(),
  61 + orderItem.getSkuId(), orderItem.getCount());
  62 +
  63 + // 3.1 记录优惠明细
  64 + int discountPrice = orderItem.getPayPrice(); // 情况一:单使用积分兑换
  65 + Assert.isTrue(activity.getPoint() >= 1, "积分商城商品兑换积分必须大于 1");
  66 + result.setUsePoint(activity.getPoint() * orderItem.getCount());
  67 + orderItem.setUsePoint(activity.getPoint() * orderItem.getCount());
  68 + if (activity.getPrice() != null && activity.getPrice() > 0) { // 情况二:积分 + 金额
  69 + discountPrice = orderItem.getPayPrice() - activity.getPrice() * orderItem.getCount();
  70 + }
  71 + // 3.2 记录优惠明细
  72 + TradePriceCalculatorHelper.addPromotion(result, orderItem,
  73 + param.getPointActivityId(), "积分商城活动", PromotionTypeEnum.POINT.getType(),
  74 + StrUtil.format("积分商城活动:省 {} 元", TradePriceCalculatorHelper.formatPrice(discountPrice)),
  75 + discountPrice);
  76 +
  77 + // 3.3 更新 SKU 优惠金额
  78 + orderItem.setDiscountPrice(orderItem.getDiscountPrice() + discountPrice);
  79 + TradePriceCalculatorHelper.recountPayPrice(orderItem);
  80 + TradePriceCalculatorHelper.recountAllPrice(result);
  81 + }
  82 +
  83 + private PointValidateJoinRespDTO validateJoinSeckill(Long userId, Long activityId, Long skuId, Integer count) {
  84 + // 1. 校验是否可以参与积分商城活动
  85 + PointValidateJoinRespDTO pointValidateJoinRespDTO = pointActivityApi.validateJoinPointActivity(activityId, skuId, count);
  86 + // 2. 校验总限购数量,目前只有 trade 有具体下单的数据,需要交给 trade 价格计算使用
  87 + int activityProductCount = tradeOrderQueryService.getSeckillProductCount(userId, activityId);
  88 + if (activityProductCount + count > pointValidateJoinRespDTO.getCount()) {
  89 + throw exception(PRICE_CALCULATE_POINT_TOTAL_LIMIT_COUNT);
  90 + }
  91 + return pointValidateJoinRespDTO;
  92 + }
  93 +
  94 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointUsePriceCalculator.java
1 1 package cn.iocoder.yudao.module.trade.service.price.calculator;
2 2  
3 3 import cn.hutool.core.util.BooleanUtil;
  4 +import cn.hutool.core.util.ObjectUtil;
4 5 import cn.hutool.core.util.StrUtil;
5 6 import cn.iocoder.yudao.module.member.api.config.MemberConfigApi;
6 7 import cn.iocoder.yudao.module.member.api.config.dto.MemberConfigRespDTO;
7 8 import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
8 9 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
9 10 import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum;
  11 +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
10 12 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
11 13 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
12 14 import jakarta.annotation.Resource;
... ... @@ -37,6 +39,10 @@ public class TradePointUsePriceCalculator implements TradePriceCalculator {
37 39  
38 40 @Override
39 41 public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
  42 + // 判断订单类型是否不为积分商城活动
  43 + if (ObjectUtil.equal(result.getType(), TradeOrderTypeEnum.POINT.getType())) {
  44 + return;
  45 + }
40 46 // 0. 初始化积分
41 47 MemberUserRespDTO user = memberUserApi.getUser(param.getUserId());
42 48 result.setTotalPoint(user.getPoint()).setUsePoint(0);
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculator.java
... ... @@ -16,6 +16,7 @@ public interface TradePriceCalculator {
16 16 int ORDER_SECKILL_ACTIVITY = 8;
17 17 int ORDER_BARGAIN_ACTIVITY = 8;
18 18 int ORDER_COMBINATION_ACTIVITY = 8;
  19 + int ORDER_POINT_ACTIVITY = 8;
19 20  
20 21 int ORDER_DISCOUNT_ACTIVITY = 10;
21 22 int ORDER_REWARD_ACTIVITY = 20;
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java
... ... @@ -90,6 +90,9 @@ public class TradePriceCalculatorHelper {
90 90 if (param.getBargainRecordId() != null) {
91 91 return TradeOrderTypeEnum.BARGAIN.getType();
92 92 }
  93 + if (param.getPointActivityId() != null) {
  94 + return TradeOrderTypeEnum.POINT.getType();
  95 + }
93 96 return TradeOrderTypeEnum.NORMAL.getType();
94 97 }
95 98  
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeSeckillActivityPriceCalculator.java
... ... @@ -8,11 +8,10 @@ import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum;
8 8 import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
9 9 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
10 10 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
  11 +import jakarta.annotation.Resource;
11 12 import org.springframework.core.annotation.Order;
12 13 import org.springframework.stereotype.Component;
13 14  
14   -import jakarta.annotation.Resource;
15   -
16 15 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
17 16 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PRICE_CALCULATE_SECKILL_TOTAL_LIMIT_COUNT;
18 17  
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/address/MemberAddressDO.java
1 1 package cn.iocoder.yudao.module.member.dal.dataobject.address;
2 2  
3 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import com.baomidou.mybatisplus.annotation.KeySequence;
4 5 import com.baomidou.mybatisplus.annotation.TableId;
5 6 import com.baomidou.mybatisplus.annotation.TableName;
6 7 import lombok.*;
... ... @@ -11,6 +12,7 @@ import lombok.*;
11 12 * @author 芋道源码
12 13 */
13 14 @TableName("member_address")
  15 +@KeySequence("member_address_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
14 16 @Data
15 17 @EqualsAndHashCode(callSuper = true)
16 18 @ToString(callSuper = true)
... ...
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/dto/PayOrderRespDTO.java
... ... @@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.pay.api.order.dto;
3 3 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
4 4 import lombok.Data;
5 5  
  6 +import java.time.LocalDateTime;
  7 +
6 8 /**
7 9 * 支付单信息 Response DTO
8 10 *
... ... @@ -41,6 +43,11 @@ public class PayOrderRespDTO {
41 43 */
42 44 private Integer status;
43 45  
  46 + /**
  47 + * 订单支付成功时间
  48 + */
  49 + private LocalDateTime successTime;
  50 +
44 51 // ========== 渠道相关字段 ==========
45 52  
46 53 }
... ...
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundRespDTO.java
... ... @@ -18,6 +18,13 @@ public class PayRefundRespDTO {
18 18 */
19 19 private Long id;
20 20  
  21 + /**
  22 + * 渠道编码
  23 + *
  24 + * 枚举 PayChannelEnum
  25 + */
  26 + private String channelCode;
  27 +
21 28 // ========== 退款相关字段 ==========
22 29 /**
23 30 * 退款状态
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/refund/PayRefundDO.java
... ... @@ -59,7 +59,7 @@ public class PayRefundDO extends BaseDO {
59 59 */
60 60 private Long channelId;
61 61 /**
62   - * 商户编码
  62 + * 渠道编码
63 63 *
64 64 * 枚举 {@link PayChannelEnum}
65 65 */
... ...
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java
... ... @@ -88,6 +88,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient&lt;WxPayClientC
88 88 throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion()));
89 89 }
90 90 } catch (WxPayException e) {
  91 + log.error("[doUnifiedOrder][退款({}) 发起微信支付异常", reqDTO, e);
91 92 String errorCode = getErrorCode(e);
92 93 String errorMessage = getErrorMessage(e);
93 94 return PayOrderRespDTO.closedOf(errorCode, errorMessage,
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailAccountDO.java
1 1 package cn.iocoder.yudao.module.system.dal.dataobject.mail;
2 2  
3 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import com.baomidou.mybatisplus.annotation.KeySequence;
4 5 import com.baomidou.mybatisplus.annotation.TableId;
5 6 import com.baomidou.mybatisplus.annotation.TableName;
6 7 import lombok.Data;
... ... @@ -15,6 +16,7 @@ import lombok.EqualsAndHashCode;
15 16 * @since 2022-03-21
16 17 */
17 18 @TableName(value = "system_mail_account", autoResultMap = true)
  19 +@KeySequence("system_mail_account_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
18 20 @Data
19 21 @EqualsAndHashCode(callSuper = true)
20 22 public class MailAccountDO extends BaseDO {
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailLogDO.java
... ... @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.dal.dataobject.mail;
3 3 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
4 4 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
5 5 import cn.iocoder.yudao.module.system.enums.mail.MailSendStatusEnum;
  6 +import com.baomidou.mybatisplus.annotation.KeySequence;
6 7 import com.baomidou.mybatisplus.annotation.TableField;
7 8 import com.baomidou.mybatisplus.annotation.TableName;
8 9 import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
... ... @@ -20,6 +21,7 @@ import java.util.Map;
20 21 * @since 2022-03-21
21 22 */
22 23 @TableName(value = "system_mail_log", autoResultMap = true)
  24 +@KeySequence("system_mail_log_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
23 25 @Data
24 26 @EqualsAndHashCode(callSuper = true)
25 27 @ToString(callSuper = true)
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailTemplateDO.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.dal.dataobject.mail;
2 2  
3 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 4 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  5 +import com.baomidou.mybatisplus.annotation.KeySequence;
5 6 import com.baomidou.mybatisplus.annotation.TableField;
6 7 import com.baomidou.mybatisplus.annotation.TableName;
7 8 import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
... ... @@ -17,6 +18,7 @@ import java.util.List;
17 18 * @since 2022-03-21
18 19 */
19 20 @TableName(value = "system_mail_template", autoResultMap = true)
  21 +@KeySequence("system_mail_template_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
20 22 @Data
21 23 @EqualsAndHashCode(callSuper = true)
22 24 public class MailTemplateDO extends BaseDO {
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceImpl.java
... ... @@ -132,8 +132,12 @@ public class PermissionServiceImpl implements PermissionService {
132 132  
133 133 @Override
134 134 @DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换
135   - @CacheEvict(value = RedisKeyConstants.MENU_ROLE_ID_LIST,
  135 + @Caching(evict = {
  136 + @CacheEvict(value = RedisKeyConstants.MENU_ROLE_ID_LIST,
  137 + allEntries = true),
  138 + @CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST,
136 139 allEntries = true) // allEntries 清空所有缓存,主要一次更新涉及到的 menuIds 较多,反倒批量会更快
  140 + })
137 141 public void assignRoleMenu(Long roleId, Set<Long> menuIds) {
138 142 // 获得角色拥有菜单编号
139 143 Set<Long> dbMenuIds = convertSet(roleMenuMapper.selectListByRoleId(roleId), RoleMenuDO::getMenuId);
... ...
yudao-server/pom.xml
... ... @@ -46,11 +46,11 @@
46 46 <!-- <version>${revision}</version>-->
47 47 <!-- </dependency>-->
48 48 <!-- 工作流。默认注释,保证编译速度 -->
49   - <dependency>
50   - <groupId>cn.iocoder.boot</groupId>
51   - <artifactId>yudao-module-bpm-biz</artifactId>
52   - <version>${revision}</version>
53   - </dependency>
  49 +<!-- <dependency>-->
  50 +<!-- <groupId>cn.iocoder.boot</groupId>-->
  51 +<!-- <artifactId>yudao-module-bpm-biz</artifactId>-->
  52 +<!-- <version>${revision}</version>-->
  53 +<!-- </dependency>-->
54 54 <!-- 支付服务。默认注释,保证编译速度 -->
55 55 <!-- <dependency>-->
56 56 <!-- <groupId>cn.iocoder.boot</groupId>-->
... ...