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

 Conflicts:
	yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/impl/SysAuthServiceImpl.java
	yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/SysAuthServiceImplTest.java
	yudao-dependencies/pom.xml
	yudao-framework/pom.xml
	yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/service/auth/impl/SysAuthServiceImpl.java
This commit is contained in:
YunaiV 2021-12-15 09:26:47 +08:00
commit 712067979c
743 changed files with 63206 additions and 1997 deletions

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
*.sql linguist-language=java

View File

@ -33,6 +33,7 @@
| | 菜单管理 | 配置系统菜单,操作权限,按钮权限标识等 |
| | 部门管理 | 配置系统组织机构(公司、部门、小组),树结构展现支持数据权限 |
| | 岗位管理 | 配置系统用户所属担任职务 |
| | 租户管理 | 配置系统租户,支持 SaaS 场景下的多租户功能 |
| | 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护 |
| 🚀 | 短信管理 | 短信渠道、短息模板、短信日志,对接阿里云、云片等主流短信平台 |
| 🚀 | 操作日志 | 系统正常操作日志记录和查询,集成 Swagger 生成日志内容 |

BIN
img.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

View File

@ -1,17 +1,17 @@
/*
Navicat Premium Data Transfer
Source Server : local-mysql001
Source Server : 127.0.0.1
Source Server Type : MySQL
Source Server Version : 50718
Source Server Version : 80026
Source Host : localhost:3306
Source Schema : ruoyi-vue-pro
Target Server Type : MySQL
Target Server Version : 50718
Target Server Version : 80026
File Encoding : 65001
Date: 03/05/2021 12:01:37
Date: 30/10/2021 13:46:03
*/
SET NAMES utf8mb4;
@ -29,7 +29,7 @@ CREATE TABLE `QRTZ_BLOB_TRIGGERS` (
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
KEY `SCHED_NAME` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
CONSTRAINT `qrtz_blob_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- ----------------------------
-- Records of QRTZ_BLOB_TRIGGERS
@ -46,7 +46,7 @@ CREATE TABLE `QRTZ_CALENDARS` (
`CALENDAR_NAME` varchar(190) NOT NULL,
`CALENDAR` blob NOT NULL,
PRIMARY KEY (`SCHED_NAME`,`CALENDAR_NAME`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- ----------------------------
-- Records of QRTZ_CALENDARS
@ -66,12 +66,13 @@ CREATE TABLE `QRTZ_CRON_TRIGGERS` (
`TIME_ZONE_ID` varchar(80) DEFAULT NULL,
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
CONSTRAINT `qrtz_cron_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- ----------------------------
-- Records of QRTZ_CRON_TRIGGERS
-- ----------------------------
BEGIN;
INSERT INTO `QRTZ_CRON_TRIGGERS` VALUES ('schedulerName', 'payNotifyJob', 'DEFAULT', '* * * * * ?', 'Asia/Shanghai');
INSERT INTO `QRTZ_CRON_TRIGGERS` VALUES ('schedulerName', 'sysUserSessionTimeoutJob', 'DEFAULT', '0 * * * * ? *', 'Asia/Shanghai');
COMMIT;
@ -85,9 +86,9 @@ CREATE TABLE `QRTZ_FIRED_TRIGGERS` (
`TRIGGER_NAME` varchar(190) NOT NULL,
`TRIGGER_GROUP` varchar(190) NOT NULL,
`INSTANCE_NAME` varchar(190) NOT NULL,
`FIRED_TIME` bigint(13) NOT NULL,
`SCHED_TIME` bigint(13) NOT NULL,
`PRIORITY` int(11) NOT NULL,
`FIRED_TIME` bigint NOT NULL,
`SCHED_TIME` bigint NOT NULL,
`PRIORITY` int NOT NULL,
`STATE` varchar(16) NOT NULL,
`JOB_NAME` varchar(190) DEFAULT NULL,
`JOB_GROUP` varchar(190) DEFAULT NULL,
@ -100,7 +101,7 @@ CREATE TABLE `QRTZ_FIRED_TRIGGERS` (
KEY `IDX_QRTZ_FT_JG` (`SCHED_NAME`,`JOB_GROUP`),
KEY `IDX_QRTZ_FT_T_G` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
KEY `IDX_QRTZ_FT_TG` (`SCHED_NAME`,`TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- ----------------------------
-- Records of QRTZ_FIRED_TRIGGERS
@ -126,12 +127,13 @@ CREATE TABLE `QRTZ_JOB_DETAILS` (
PRIMARY KEY (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),
KEY `IDX_QRTZ_J_REQ_RECOVERY` (`SCHED_NAME`,`REQUESTS_RECOVERY`),
KEY `IDX_QRTZ_J_GRP` (`SCHED_NAME`,`JOB_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- ----------------------------
-- Records of QRTZ_JOB_DETAILS
-- ----------------------------
BEGIN;
INSERT INTO `QRTZ_JOB_DETAILS` VALUES ('schedulerName', 'payNotifyJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000057400104A4F425F48414E444C45525F4E414D4574000C7061794E6F746966794A6F627800);
INSERT INTO `QRTZ_JOB_DETAILS` VALUES ('schedulerName', 'sysUserSessionTimeoutJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000037400104A4F425F48414E444C45525F4E414D457400187379735573657253657373696F6E54696D656F75744A6F627800);
COMMIT;
@ -143,7 +145,7 @@ CREATE TABLE `QRTZ_LOCKS` (
`SCHED_NAME` varchar(120) NOT NULL,
`LOCK_NAME` varchar(40) NOT NULL,
PRIMARY KEY (`SCHED_NAME`,`LOCK_NAME`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- ----------------------------
-- Records of QRTZ_LOCKS
@ -161,7 +163,7 @@ CREATE TABLE `QRTZ_PAUSED_TRIGGER_GRPS` (
`SCHED_NAME` varchar(120) NOT NULL,
`TRIGGER_GROUP` varchar(190) NOT NULL,
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- ----------------------------
-- Records of QRTZ_PAUSED_TRIGGER_GRPS
@ -176,16 +178,16 @@ DROP TABLE IF EXISTS `QRTZ_SCHEDULER_STATE`;
CREATE TABLE `QRTZ_SCHEDULER_STATE` (
`SCHED_NAME` varchar(120) NOT NULL,
`INSTANCE_NAME` varchar(190) NOT NULL,
`LAST_CHECKIN_TIME` bigint(13) NOT NULL,
`CHECKIN_INTERVAL` bigint(13) NOT NULL,
`LAST_CHECKIN_TIME` bigint NOT NULL,
`CHECKIN_INTERVAL` bigint NOT NULL,
PRIMARY KEY (`SCHED_NAME`,`INSTANCE_NAME`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- ----------------------------
-- Records of QRTZ_SCHEDULER_STATE
-- ----------------------------
BEGIN;
INSERT INTO `QRTZ_SCHEDULER_STATE` VALUES ('schedulerName', 'Yunai1620010117445', 1620010210071, 15000);
INSERT INTO `QRTZ_SCHEDULER_STATE` VALUES ('schedulerName', 'Yunai.local1635571630493', 1635572537879, 15000);
COMMIT;
-- ----------------------------
@ -196,12 +198,12 @@ CREATE TABLE `QRTZ_SIMPLE_TRIGGERS` (
`SCHED_NAME` varchar(120) NOT NULL,
`TRIGGER_NAME` varchar(190) NOT NULL,
`TRIGGER_GROUP` varchar(190) NOT NULL,
`REPEAT_COUNT` bigint(7) NOT NULL,
`REPEAT_INTERVAL` bigint(12) NOT NULL,
`TIMES_TRIGGERED` bigint(10) NOT NULL,
`REPEAT_COUNT` bigint NOT NULL,
`REPEAT_INTERVAL` bigint NOT NULL,
`TIMES_TRIGGERED` bigint NOT NULL,
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
CONSTRAINT `qrtz_simple_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- ----------------------------
-- Records of QRTZ_SIMPLE_TRIGGERS
@ -220,17 +222,17 @@ CREATE TABLE `QRTZ_SIMPROP_TRIGGERS` (
`STR_PROP_1` varchar(512) DEFAULT NULL,
`STR_PROP_2` varchar(512) DEFAULT NULL,
`STR_PROP_3` varchar(512) DEFAULT NULL,
`INT_PROP_1` int(11) DEFAULT NULL,
`INT_PROP_2` int(11) DEFAULT NULL,
`LONG_PROP_1` bigint(20) DEFAULT NULL,
`LONG_PROP_2` bigint(20) DEFAULT NULL,
`INT_PROP_1` int DEFAULT NULL,
`INT_PROP_2` int DEFAULT NULL,
`LONG_PROP_1` bigint DEFAULT NULL,
`LONG_PROP_2` bigint DEFAULT NULL,
`DEC_PROP_1` decimal(13,4) DEFAULT NULL,
`DEC_PROP_2` decimal(13,4) DEFAULT NULL,
`BOOL_PROP_1` varchar(1) DEFAULT NULL,
`BOOL_PROP_2` varchar(1) DEFAULT NULL,
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
CONSTRAINT `qrtz_simprop_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- ----------------------------
-- Records of QRTZ_SIMPROP_TRIGGERS
@ -249,15 +251,15 @@ CREATE TABLE `QRTZ_TRIGGERS` (
`JOB_NAME` varchar(190) NOT NULL,
`JOB_GROUP` varchar(190) NOT NULL,
`DESCRIPTION` varchar(250) DEFAULT NULL,
`NEXT_FIRE_TIME` bigint(13) DEFAULT NULL,
`PREV_FIRE_TIME` bigint(13) DEFAULT NULL,
`PRIORITY` int(11) DEFAULT NULL,
`NEXT_FIRE_TIME` bigint DEFAULT NULL,
`PREV_FIRE_TIME` bigint DEFAULT NULL,
`PRIORITY` int DEFAULT NULL,
`TRIGGER_STATE` varchar(16) NOT NULL,
`TRIGGER_TYPE` varchar(8) NOT NULL,
`START_TIME` bigint(13) NOT NULL,
`END_TIME` bigint(13) DEFAULT NULL,
`START_TIME` bigint NOT NULL,
`END_TIME` bigint DEFAULT NULL,
`CALENDAR_NAME` varchar(190) DEFAULT NULL,
`MISFIRE_INSTR` smallint(2) DEFAULT NULL,
`MISFIRE_INSTR` smallint DEFAULT NULL,
`JOB_DATA` blob,
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
KEY `IDX_QRTZ_T_J` (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),
@ -273,13 +275,14 @@ CREATE TABLE `QRTZ_TRIGGERS` (
KEY `IDX_QRTZ_T_NFT_ST_MISFIRE` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`,`TRIGGER_STATE`),
KEY `IDX_QRTZ_T_NFT_ST_MISFIRE_GRP` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),
CONSTRAINT `qrtz_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) REFERENCES `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- ----------------------------
-- Records of QRTZ_TRIGGERS
-- ----------------------------
BEGIN;
INSERT INTO `QRTZ_TRIGGERS` VALUES ('schedulerName', 'sysUserSessionTimeoutJob', 'DEFAULT', 'sysUserSessionTimeoutJob', 'DEFAULT', NULL, 1620010260000, 1620010200000, 5, 'WAITING', 'CRON', 1613649236000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D707400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B0200007870000007D074000F4A4F425F52455452595F434F554E547371007E0009000000037800);
INSERT INTO `QRTZ_TRIGGERS` VALUES ('schedulerName', 'payNotifyJob', 'DEFAULT', 'payNotifyJob', 'DEFAULT', NULL, 1635572540000, 1635572539000, 5, 'WAITING', 'CRON', 1635294882000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D707400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E5471007E000B7800);
INSERT INTO `QRTZ_TRIGGERS` VALUES ('schedulerName', 'sysUserSessionTimeoutJob', 'DEFAULT', 'sysUserSessionTimeoutJob', 'DEFAULT', NULL, 1635572580000, 1635572520000, 5, 'WAITING', 'CRON', 1613649236000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D707400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B0200007870000007D074000F4A4F425F52455452595F434F554E547371007E0009000000037800);
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;

File diff suppressed because one or more lines are too long

View File

@ -36,6 +36,11 @@
<artifactId>yudao-spring-boot-starter-biz-sms</artifactId>
</dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-activiti</artifactId>
</dependency>
<!-- Web 相关 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
@ -112,6 +117,16 @@
<artifactId>yudao-spring-boot-starter-excel</artifactId>
</dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-tenant</artifactId>
</dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-data-permission</artifactId>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>

View File

@ -1,9 +0,0 @@
package cn.iocoder.yudao.adminserver.framework.async.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
@Configuration
@EnableAsync
public class AsyncConfiguration {
}

View File

@ -1,4 +0,0 @@
/**
* 异步执行基于 Spring @Async 实现
*/
package cn.iocoder.yudao.adminserver.framework.async;

View File

@ -22,9 +22,11 @@ public class SecurityConfiguration {
@Bean
public Customizer<ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry> authorizeRequestsCustomizer() {
return registry -> {
// 通用的接口可匿名访问 TODO 芋艿需要抽象出去
// 验证码的接口
registry.antMatchers(api("/system/captcha/**")).anonymous();
// Spring Boot Admin Server 的安全配置 TODO 芋艿需要抽象出去
// 获得租户编号的接口
registry.antMatchers(api("/system/tenant/get-id-by-name")).anonymous();
// Spring Boot Admin Server 的安全配置
registry.antMatchers(adminSeverContextPath).anonymous()
.antMatchers(adminSeverContextPath + "/**").anonymous();
// 短信回调 API

View File

@ -0,0 +1,100 @@
package cn.iocoder.yudao.adminserver.modules.activiti.controller.form;
import cn.iocoder.yudao.adminserver.modules.activiti.controller.form.vo.*;
import cn.iocoder.yudao.adminserver.modules.activiti.convert.form.WfFormConvert;
import cn.iocoder.yudao.adminserver.modules.activiti.dal.dataobject.form.WfForm;
import cn.iocoder.yudao.adminserver.modules.activiti.service.form.WfFormService;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
// TODO @风里雾里 Os=Wf/os 改成 /wl 开头目前这个模块咱先定位成给工作流用的
@Api(tags = "动态表单")
@RestController
@RequestMapping("/wl/form")
@Validated
public class WlFormController {
@Resource
private WfFormService formService;
@PostMapping("/create")
@ApiOperation("创建动态表单")
@PreAuthorize("@ss.hasPermission('os:form:create')")
public CommonResult<Long> createForm(@Valid @RequestBody WfFormCreateReqVO createReqVO) {
return success(formService.createForm(createReqVO));
}
@PutMapping("/update")
@ApiOperation("更新动态表单")
@PreAuthorize("@ss.hasPermission('os:form:update')")
public CommonResult<Boolean> updateForm(@Valid @RequestBody WfFormUpdateReqVO updateReqVO) {
formService.updateForm(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@ApiOperation("删除动态表单")
@ApiImplicitParam(name = "id", value = "编号", required = true)
@PreAuthorize("@ss.hasPermission('os:form:delete')")
public CommonResult<Boolean> deleteForm(@RequestParam("id") Long id) {
formService.deleteForm(id);
return success(true);
}
@GetMapping("/get")
@ApiOperation("获得动态表单")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('os:form:query')")
public CommonResult<WfFormRespVO> getForm(@RequestParam("id") Long id) {
WfForm form = formService.getForm(id);
return success(WfFormConvert.INSTANCE.convert(form));
}
@GetMapping("/list")
@ApiOperation("获得动态表单列表")
@ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class)
@PreAuthorize("@ss.hasPermission('os:form:query')")
public CommonResult<List<WfFormRespVO>> getFormList(@RequestParam("ids") Collection<Long> ids) {
List<WfForm> list = formService.getFormList(ids);
return success(WfFormConvert.INSTANCE.convertList(list));
}
@GetMapping("/page")
@ApiOperation("获得动态表单分页")
@PreAuthorize("@ss.hasPermission('os:form:query')")
public CommonResult<PageResult<WfFormRespVO>> getFormPage(@Valid WfFormPageReqVO pageVO) {
PageResult<WfForm> pageResult = formService.getFormPage(pageVO);
return success(WfFormConvert.INSTANCE.convertPage(pageResult));
}
@GetMapping("/export-excel")
@ApiOperation("导出动态表单 Excel")
@PreAuthorize("@ss.hasPermission('os:form:export')")
@OperateLog(type = EXPORT)
public void exportFormExcel(@Valid WfFormExportReqVO exportReqVO,
HttpServletResponse response) throws IOException {
List<WfForm> list = formService.getFormList(exportReqVO);
// 导出 Excel
List<WfFormExcelVO> datas = WfFormConvert.INSTANCE.convertList02(list);
ExcelUtils.write(response, "动态表单.xls", "数据", WfFormExcelVO.class, datas);
}
}

View File

@ -0,0 +1,28 @@
package cn.iocoder.yudao.adminserver.modules.activiti.controller.form.vo;
import lombok.*;
import io.swagger.annotations.*;
import javax.validation.constraints.*;
/**
* 动态表单 Base VO提供给添加修改详细的子 VO 使用
* 如果子 VO 存在差异的字段请不要添加到这里影响 Swagger 文档生成
*/
@Data
public class WfFormBaseVO {
@ApiModelProperty(value = "表单名称", required = true)
@NotNull(message = "表单名称不能为空")
private String name;
@ApiModelProperty(value = "商户状态", required = true)
@NotNull(message = "商户状态不能为空")
private Integer status;
@ApiModelProperty(value = "表单JSON")
private String formJson;
@ApiModelProperty(value = "备注")
private String remark;
}

View File

@ -0,0 +1,12 @@
package cn.iocoder.yudao.adminserver.modules.activiti.controller.form.vo;
import lombok.*;
import io.swagger.annotations.*;
@ApiModel("动态表单创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class WfFormCreateReqVO extends WfFormBaseVO {
}

View File

@ -0,0 +1,34 @@
package cn.iocoder.yudao.adminserver.modules.activiti.controller.form.vo;
import lombok.*;
import java.util.*;
import com.alibaba.excel.annotation.ExcelProperty;
/**
* 动态表单 Excel VO
*
* @author 芋艿
*/
@Data
public class WfFormExcelVO {
@ExcelProperty("表单编号")
private Long id;
@ExcelProperty("表单名称")
private String name;
@ExcelProperty("商户状态")
private Integer status;
@ExcelProperty("表单JSON")
private String formJson;
@ExcelProperty("备注")
private String remark;
@ExcelProperty("创建时间")
private Date createTime;
}

View File

@ -0,0 +1,33 @@
package cn.iocoder.yudao.adminserver.modules.activiti.controller.form.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import org.springframework.format.annotation.DateTimeFormat;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel(value = "动态表单 Excel 导出 Request VO", description = "参数和 OsFormPageReqVO 是一致的")
@Data
public class WfFormExportReqVO {
@ApiModelProperty(value = "表单名称")
private String name;
@ApiModelProperty(value = "商户状态")
private Integer status;
@ApiModelProperty(value = "表单JSON")
private String formJson;
@ApiModelProperty(value = "备注")
private String remark;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "开始创建时间")
private Date beginCreateTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "结束创建时间")
private Date endCreateTime;
}

View File

@ -0,0 +1,36 @@
package cn.iocoder.yudao.adminserver.modules.activiti.controller.form.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import org.springframework.format.annotation.DateTimeFormat;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel("动态表单分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class WfFormPageReqVO extends PageParam {
@ApiModelProperty(value = "表单名称")
private String name;
@ApiModelProperty(value = "商户状态")
private Integer status;
@ApiModelProperty(value = "表单JSON")
private String formJson;
@ApiModelProperty(value = "备注")
private String remark;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "开始创建时间")
private Date beginCreateTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "结束创建时间")
private Date endCreateTime;
}

View File

@ -0,0 +1,19 @@
package cn.iocoder.yudao.adminserver.modules.activiti.controller.form.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
@ApiModel("动态表单 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class WfFormRespVO extends WfFormBaseVO {
@ApiModelProperty(value = "表单编号", required = true)
private Long id;
@ApiModelProperty(value = "创建时间", required = true)
private Date createTime;
}

View File

@ -0,0 +1,17 @@
package cn.iocoder.yudao.adminserver.modules.activiti.controller.form.vo;
import lombok.*;
import io.swagger.annotations.*;
import javax.validation.constraints.*;
@ApiModel("动态表单更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class WfFormUpdateReqVO extends WfFormBaseVO {
@ApiModelProperty(value = "表单编号", required = true)
@NotNull(message = "表单编号不能为空")
private Long id;
}

View File

@ -0,0 +1,114 @@
package cn.iocoder.yudao.adminserver.modules.activiti.controller.oa;
import cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo.*;
import cn.iocoder.yudao.adminserver.modules.activiti.convert.oa.OaLeaveConvert;
import cn.iocoder.yudao.adminserver.modules.activiti.dal.dataobject.oa.OaLeaveDO;
import cn.iocoder.yudao.adminserver.modules.activiti.service.oa.OaLeaveService;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
// TODO @jasonOa=OA 会不会好点名词缩写哈
@Api(tags = "请假申请")
@RestController
@RequestMapping("/oa/leave")
@Validated
public class OaLeaveController {
@Resource
private OaLeaveService leaveService;
@PostMapping("/create")
@ApiOperation("创建请假申请")
@PreAuthorize("@ss.hasPermission('oa:leave:create')")
public CommonResult<Long> createLeave(@Valid @RequestBody OaLeaveCreateReqVO createReqVO) {
// TODO @芋艿processKey 自己去理解下不过得把 leave 变成枚举
createReqVO.setProcessKey("leave");
return success(leaveService.createLeave(createReqVO));
}
@PostMapping("/form-key/create")
@ApiOperation("创建外置请假申请")
public CommonResult<Long> createFormKeyLeave(@Valid @RequestBody OaLeaveCreateReqVO createReqVO) {
// TODO @芋艿processKey 自己去理解下不过得把 formkey 变成枚举
createReqVO.setProcessKey("leave-formkey");
return success(leaveService.createLeave(createReqVO));
}
@PutMapping("/update")
@ApiOperation("更新请假申请")
@PreAuthorize("@ss.hasPermission('oa:leave:update')")
public CommonResult<Boolean> updateLeave(@Valid @RequestBody OaLeaveUpdateReqVO updateReqVO) {
leaveService.updateLeave(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@ApiOperation("删除请假申请")
@ApiImplicitParam(name = "id", value = "编号", required = true)
@PreAuthorize("@ss.hasPermission('oa:leave:delete')")
public CommonResult<Boolean> deleteLeave(@RequestParam("id") Long id) {
leaveService.deleteLeave(id);
return success(true);
}
@GetMapping("/get")
@ApiOperation("获得请假申请")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('oa:leave:query')")
public CommonResult<OaLeaveRespVO> getLeave(@RequestParam("id") Long id) {
OaLeaveDO leave = leaveService.getLeave(id);
return success(OaLeaveConvert.INSTANCE.convert(leave));
}
@GetMapping("/list")
@ApiOperation("获得请假申请列表")
@ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class)
@PreAuthorize("@ss.hasPermission('oa:leave:query')")
public CommonResult<List<OaLeaveRespVO>> getLeaveList(@RequestParam("ids") Collection<Long> ids) {
List<OaLeaveDO> list = leaveService.getLeaveList(ids);
return success(OaLeaveConvert.INSTANCE.convertList(list));
}
@GetMapping("/page")
@ApiOperation("获得请假申请分页")
@PreAuthorize("@ss.hasPermission('oa:leave:query')")
public CommonResult<PageResult<OaLeaveRespVO>> getLeavePage(@Valid OaLeavePageReqVO pageVO) {
//值查询自己申请请假
// TODO @芋艿这里的传值到底前端搞还是后端搞
pageVO.setUserId(SecurityFrameworkUtils.getLoginUser().getUsername());
PageResult<OaLeaveDO> pageResult = leaveService.getLeavePage(pageVO);
return success(OaLeaveConvert.INSTANCE.convertPage(pageResult));
}
@GetMapping("/export-excel")
@ApiOperation("导出请假申请 Excel")
@PreAuthorize("@ss.hasPermission('oa:leave:export')")
@OperateLog(type = EXPORT)
public void exportLeaveExcel(@Valid OaLeaveExportReqVO exportReqVO,
HttpServletResponse response) throws IOException {
List<OaLeaveDO> list = leaveService.getLeaveList(exportReqVO);
// 导出 Excel
List<OaLeaveExcelVO> datas = OaLeaveConvert.INSTANCE.convertList02(list);
ExcelUtils.write(response, "请假申请.xls", "数据", OaLeaveExcelVO.class, datas);
}
}

View File

@ -0,0 +1,48 @@
package cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import javax.validation.constraints.*;
import org.springframework.format.annotation.DateTimeFormat;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
/**
* 请假申请 Base VO提供给添加修改详细的子 VO 使用
* 如果子 VO 存在差异的字段请不要添加到这里影响 Swagger 文档生成
*/
@Data
public class OaLeaveBaseVO {
@ApiModelProperty(value = "流程id")
private String processInstanceId;
@ApiModelProperty(value = "状态", required = true)
private Integer status;
@ApiModelProperty(value = "申请人id", required = true)
private String userId;
@ApiModelProperty(value = "开始时间", required = true)
@NotNull(message = "开始时间不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date startTime;
@ApiModelProperty(value = "结束时间", required = true)
@NotNull(message = "结束时间不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date endTime;
@ApiModelProperty(value = "请假类型")
private String leaveType;
@ApiModelProperty(value = "原因")
private String reason;
@ApiModelProperty(value = "申请时间", required = true)
@NotNull(message = "申请时间不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date applyTime;
}

View File

@ -0,0 +1,15 @@
package cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import javax.validation.constraints.*;
@ApiModel("请假申请创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class OaLeaveCreateReqVO extends OaLeaveBaseVO {
private String processKey;
}

View File

@ -0,0 +1,44 @@
package cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import com.alibaba.excel.annotation.ExcelProperty;
/**
* 请假申请 Excel VO
*
* @author 芋艿
*/
@Data
public class OaLeaveExcelVO {
@ExcelProperty("请假表单主键")
private Long id;
@ExcelProperty("流程id")
private String processInstanceId;
@ExcelProperty("状态")
private Integer status;
@ExcelProperty("申请人id")
private String userId;
@ExcelProperty("开始时间")
private Date startTime;
@ExcelProperty("结束时间")
private Date endTime;
@ExcelProperty("请假类型")
private String leaveType;
@ExcelProperty("原因")
private String reason;
@ExcelProperty("申请时间")
private Date applyTime;
}

View File

@ -0,0 +1,54 @@
package cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import org.springframework.format.annotation.DateTimeFormat;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel(value = "请假申请 Excel 导出 Request VO", description = "参数和 OaLeavePageReqVO 是一致的")
@Data
public class OaLeaveExportReqVO {
@ApiModelProperty(value = "流程id")
private String processInstanceId;
@ApiModelProperty(value = "状态")
private Integer status;
@ApiModelProperty(value = "申请人id")
private String userId;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "开始开始时间")
private Date beginStartTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "结束开始时间")
private Date endStartTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "开始结束时间")
private Date beginEndTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "结束结束时间")
private Date endEndTime;
@ApiModelProperty(value = "请假类型")
private String leaveType;
@ApiModelProperty(value = "原因")
private String reason;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "开始申请时间")
private Date beginApplyTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "结束申请时间")
private Date endApplyTime;
}

View File

@ -0,0 +1,56 @@
package cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import org.springframework.format.annotation.DateTimeFormat;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel("请假申请分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class OaLeavePageReqVO extends PageParam {
@ApiModelProperty(value = "流程id")
private String processInstanceId;
@ApiModelProperty(value = "状态")
private Integer status;
@ApiModelProperty(value = "申请人id")
private String userId;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "开始开始时间")
private Date beginStartTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "结束开始时间")
private Date endStartTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "开始结束时间")
private Date beginEndTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "结束结束时间")
private Date endEndTime;
@ApiModelProperty(value = "请假类型")
private String leaveType;
@ApiModelProperty(value = "原因")
private String reason;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "开始申请时间")
private Date beginApplyTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "结束申请时间")
private Date endApplyTime;
}

View File

@ -0,0 +1,16 @@
package cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
@ApiModel("请假申请 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class OaLeaveRespVO extends OaLeaveBaseVO {
@ApiModelProperty(value = "请假表单主键", required = true)
private Long id;
}

View File

@ -0,0 +1,32 @@
package cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.validation.constraints.NotNull;
import java.util.Map;
@ApiModel("请假申请更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class OaLeaveUpdateReqVO extends OaLeaveBaseVO {
@ApiModelProperty(value = "请假表单主键", required = true)
@NotNull(message = "请假表单主键不能为空")
private Long id;
// TODO @jsonswagger validator 的注解要加哈
private String taskId;
private String comment;
private Map<String,Object> variables;
// TODO @芋艿variables 的作用是啥
}

View File

@ -0,0 +1,34 @@
package cn.iocoder.yudao.adminserver.modules.activiti.controller.workflow;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import org.activiti.api.process.runtime.ProcessRuntime;
import org.activiti.engine.RepositoryService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
// TODO @jsonswagger validation 的注解后续要补全下哈可以等 workflow 基本写的差不多之后
@RestController
@RequestMapping("/workflow/process/definition")
public class ProcessDefinitionController {
@Resource
private RepositoryService repositoryService;
@Resource
private ProcessRuntime processRuntime;
@GetMapping(value = "/getStartForm")
public CommonResult<String> getStartForm(@RequestParam("processKey") String processKey){
//这样查似乎有问题 暂时写死
// final ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().
// processDefinitionKey(processKey).latestVersion().singleResult();
// processRuntime.processDefinition(processDefinition.getId()).getFormKey();
return CommonResult.success("/flow/leave/apply");
}
}

View File

@ -0,0 +1,60 @@
package cn.iocoder.yudao.adminserver.modules.activiti.controller.workflow;
import cn.iocoder.yudao.adminserver.modules.activiti.controller.workflow.vo.*;
import cn.iocoder.yudao.adminserver.modules.activiti.service.workflow.TaskService;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
// TODO @jsonswagger validation 的注解后续要补全下哈可以等 workflow 基本写的差不多之后
@Api(tags = "工作流待办任务")
@RestController
@RequestMapping("/workflow/task")
public class TaskController {
@Resource
private TaskService taskService;
@GetMapping("/todo/page")
@ApiOperation("获取待办任务分页")
public CommonResult<PageResult<TodoTaskRespVO>> getTodoTaskPage(@Valid TodoTaskPageReqVO pageVO) {
return success(taskService.getTodoTaskPage(pageVO));
}
@GetMapping("/claim")
@ApiOperation("签收任务")
public CommonResult<Boolean> claimTask(@RequestParam("id") String taskId) {
taskService.claimTask(taskId);
return success(true);
}
@PostMapping("/task-steps")
public CommonResult<TaskHandleVO> getTaskSteps(@RequestBody TaskQueryReqVO taskQuery) {
return success(taskService.getTaskSteps(taskQuery));
}
@PostMapping("/formKey")
public CommonResult<TodoTaskRespVO> getTaskFormKey(@RequestBody TaskQueryReqVO taskQuery) {
return success(taskService.getTaskFormKey(taskQuery));
}
@PostMapping("/complete")
public CommonResult<Boolean> complete(@RequestBody TaskReqVO taskReq) {
taskService.completeTask(taskReq);
return success(true);
}
@GetMapping("/process/history-steps")
public CommonResult<List<TaskStepVO>> getHistorySteps(@RequestParam("id") String processInstanceId) {
return success(taskService.getHistorySteps(processInstanceId));
}
}

View File

@ -0,0 +1,19 @@
package cn.iocoder.yudao.adminserver.modules.activiti.controller.workflow.vo;
import lombok.Data;
import lombok.ToString;
import java.util.List;
@Data
@ToString
public class TaskHandleVO {
private Object formObject;
private List<TaskStepVO> historyTask;
private String taskVariable;
}

View File

@ -0,0 +1,15 @@
package cn.iocoder.yudao.adminserver.modules.activiti.controller.workflow.vo;
import lombok.Data;
import lombok.ToString;
@Data
@ToString
public class TaskQueryReqVO {
private String processKey;
private String taskId;
private String businessKey;
}

View File

@ -0,0 +1,17 @@
package cn.iocoder.yudao.adminserver.modules.activiti.controller.workflow.vo;
import lombok.Data;
import lombok.ToString;
import java.util.Map;
@Data
@ToString
public class TaskReqVO {
private String taskId;
private Map<String,Object> variables;
private String comment;
}

View File

@ -0,0 +1,24 @@
package cn.iocoder.yudao.adminserver.modules.activiti.controller.workflow.vo;
import lombok.Data;
import lombok.ToString;
import java.util.Date;
@Data
@ToString
public class TaskStepVO {
private String stepName;
private Date startTime;
private Date endTime;
private String assignee;
private String comment;
private Integer status;
}

View File

@ -0,0 +1,16 @@
package cn.iocoder.yudao.adminserver.modules.activiti.controller.workflow.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@ApiModel("待办任务申请分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class TodoTaskPageReqVO extends PageParam {
private String assignee;
}

View File

@ -0,0 +1,33 @@
package cn.iocoder.yudao.adminserver.modules.activiti.controller.workflow.vo;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@ApiModel("待办任务 Response VO")
@Data
@ToString
public class TodoTaskRespVO {
private String id;
/**
* 1:未签收
* 2:已签收
*/
private Integer status;
private String processName;
private String processKey;
private String businessKey;
private String formKey;
}

View File

@ -0,0 +1,36 @@
package cn.iocoder.yudao.adminserver.modules.activiti.convert.form;
import cn.iocoder.yudao.adminserver.modules.activiti.controller.form.vo.WfFormCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.activiti.controller.form.vo.WfFormExcelVO;
import cn.iocoder.yudao.adminserver.modules.activiti.controller.form.vo.WfFormRespVO;
import cn.iocoder.yudao.adminserver.modules.activiti.controller.form.vo.WfFormUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.activiti.dal.dataobject.form.WfForm;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
/**
* 动态表单 Convert
*
* @author 芋艿
*/
@Mapper
public interface WfFormConvert {
WfFormConvert INSTANCE = Mappers.getMapper(WfFormConvert.class);
WfForm convert(WfFormCreateReqVO bean);
WfForm convert(WfFormUpdateReqVO bean);
WfFormRespVO convert(WfForm bean);
List<WfFormRespVO> convertList(List<WfForm> list);
PageResult<WfFormRespVO> convertPage(PageResult<WfForm> page);
List<WfFormExcelVO> convertList02(List<WfForm> list);
}

View File

@ -0,0 +1,34 @@
package cn.iocoder.yudao.adminserver.modules.activiti.convert.oa;
import java.util.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo.*;
import cn.iocoder.yudao.adminserver.modules.activiti.dal.dataobject.oa.OaLeaveDO;
/**
* 请假申请 Convert
*
* @author 芋艿
*/
@Mapper
public interface OaLeaveConvert {
OaLeaveConvert INSTANCE = Mappers.getMapper(OaLeaveConvert.class);
OaLeaveDO convert(OaLeaveCreateReqVO bean);
OaLeaveDO convert(OaLeaveUpdateReqVO bean);
OaLeaveRespVO convert(OaLeaveDO bean);
List<OaLeaveRespVO> convertList(List<OaLeaveDO> list);
PageResult<OaLeaveRespVO> convertPage(PageResult<OaLeaveDO> page);
List<OaLeaveExcelVO> convertList02(List<OaLeaveDO> list);
}

View File

@ -0,0 +1,9 @@
package cn.iocoder.yudao.adminserver.modules.activiti.convert.workflow;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@Mapper
public interface TodoTaskConvert {
TodoTaskConvert INSTANCE = Mappers.getMapper(TodoTaskConvert.class);
}

View File

@ -0,0 +1,57 @@
package cn.iocoder.yudao.adminserver.modules.activiti.dal.dataobject.form;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.*;
import java.util.List;
/**
* 工作流的表单定义
* 用于工作流的申请表单需要动态配置的场景
*
* @author 芋道源码
*/
@TableName(value = "wf_form", autoResultMap = true)
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class WfForm extends BaseDO {
/**
* 编号
*/
@TableId
private Long id;
/**
* 表单名
*/
private String name;
/**
* 状态
*/
private Integer status;
/**
* 表单JSON
*/
private String formJson;
/**
* 表单配置
*
* 目前直接将 https://github.com/JakHuang/form-generator 生成的 JSON 直接保存
* 定义https://github.com/JakHuang/form-generator/issues/46
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private List<String> fields;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,55 @@
package cn.iocoder.yudao.adminserver.modules.activiti.dal.dataobject.form;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.*;
import java.util.List;
import java.util.Map;
/**
* 工作流的表单结果
* 用户每次填写工作流的申请表单时会保存一条记录到该表
*
* @author 芋道源码
*/
@TableName(value = "wf_form", autoResultMap = true)
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class WfFormData extends BaseDO {
/**
* 编号
*/
private Long id;
/**
* 表单编号
*
* 关联 {@link WfForm#getId()}
*/
private Long formId;
/**
* 状态
*/
private Integer status;
/**
* 表单配置
*
* 冗余 {@link WfForm#getFields()}
* 主要考虑表单是可以修改的
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private List<String> fields;
/**
* 表单值
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private Map<String, Object> values;
}

View File

@ -0,0 +1,60 @@
package cn.iocoder.yudao.adminserver.modules.activiti.dal.dataobject.oa;
import lombok.*;
import java.util.*;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
/**
* 请假申请 DO
*
* @author 芋艿
*/
@TableName("oa_leave")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class OaLeaveDO extends BaseDO {
/**
* 请假表单主键
*/
@TableId
private Long id;
/**
* 流程id
*/
private String processInstanceId;
/**
* 状态
*/
private Integer status;
/**
* 申请人id
*/
private String userId;
/**
* 开始时间
*/
private Date startTime;
/**
* 结束时间
*/
private Date endTime;
/**
* 请假类型
*/
private String leaveType;
/**
* 原因
*/
private String reason;
/**
* 申请时间
*/
private Date applyTime;
}

View File

@ -0,0 +1,29 @@
package cn.iocoder.yudao.adminserver.modules.activiti.dal.dataobject.process;
/**
* 流程模型实体类 映射 activiti ProcessDefinition接口
*
* @author ZJQ
* @date 2021/9/7 23:23
*/
public class ProcessDefinitionDO {
private String id;
private String category;
private String key;
private String name;
private String version;
private String resourceName;
private String deploymentId;
private String diagramResourceName;
private boolean suspended;
}

View File

@ -0,0 +1,43 @@
package cn.iocoder.yudao.adminserver.modules.activiti.dal.mysql.form;
import cn.iocoder.yudao.adminserver.modules.activiti.controller.form.vo.WfFormExportReqVO;
import cn.iocoder.yudao.adminserver.modules.activiti.controller.form.vo.WfFormPageReqVO;
import cn.iocoder.yudao.adminserver.modules.activiti.dal.dataobject.form.WfForm;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* 动态表单 Mapper
*
* @author 风里雾里
*/
@Mapper
public interface WfFormMapper extends BaseMapperX<WfForm> {
default PageResult<WfForm> selectPage(WfFormPageReqVO reqVO) {
return selectPage(reqVO, new QueryWrapperX<WfForm>()
.likeIfPresent("name", reqVO.getName())
.eqIfPresent("status", reqVO.getStatus())
.eqIfPresent("form_json", reqVO.getFormJson())
.eqIfPresent("remark", reqVO.getRemark())
.betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
.orderByDesc("id") );
}
default List<WfForm> selectList(WfFormExportReqVO reqVO) {
return selectList(new QueryWrapperX<WfForm>()
.likeIfPresent("name", reqVO.getName())
.eqIfPresent("status", reqVO.getStatus())
.eqIfPresent("form_json", reqVO.getFormJson())
.eqIfPresent("remark", reqVO.getRemark())
.betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
.orderByDesc("id") );
}
}

View File

@ -0,0 +1,46 @@
package cn.iocoder.yudao.adminserver.modules.activiti.dal.mysql.oa;
import java.util.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.adminserver.modules.activiti.dal.dataobject.oa.OaLeaveDO;
import org.apache.ibatis.annotations.Mapper;
import cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo.*;
/**
* 请假申请 Mapper
*
* @author 芋艿
*/
@Mapper
public interface OaLeaveMapper extends BaseMapperX<OaLeaveDO> {
default PageResult<OaLeaveDO> selectPage(OaLeavePageReqVO reqVO) {
return selectPage(reqVO, new QueryWrapperX<OaLeaveDO>()
.eqIfPresent("process_instance_id", reqVO.getProcessInstanceId())
.eqIfPresent("status", reqVO.getStatus())
.eqIfPresent("user_id", reqVO.getUserId())
.betweenIfPresent("start_time", reqVO.getBeginStartTime(), reqVO.getEndStartTime())
.betweenIfPresent("end_time", reqVO.getBeginEndTime(), reqVO.getEndEndTime())
.eqIfPresent("leave_type", reqVO.getLeaveType())
.eqIfPresent("reason", reqVO.getReason())
.betweenIfPresent("apply_time", reqVO.getBeginApplyTime(), reqVO.getEndApplyTime())
.orderByDesc("id") );
}
default List<OaLeaveDO> selectList(OaLeaveExportReqVO reqVO) {
return selectList(new QueryWrapperX<OaLeaveDO>()
.eqIfPresent("process_instance_id", reqVO.getProcessInstanceId())
.eqIfPresent("status", reqVO.getStatus())
.eqIfPresent("user_id", reqVO.getUserId())
.betweenIfPresent("start_time", reqVO.getBeginStartTime(), reqVO.getEndStartTime())
.betweenIfPresent("end_time", reqVO.getBeginEndTime(), reqVO.getEndEndTime())
.eqIfPresent("leave_type", reqVO.getLeaveType())
.eqIfPresent("reason", reqVO.getReason())
.betweenIfPresent("apply_time", reqVO.getBeginApplyTime(), reqVO.getEndApplyTime())
.orderByDesc("id") );
}
}

View File

@ -0,0 +1,13 @@
package cn.iocoder.yudao.adminserver.modules.activiti.enums;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
/**
* activiti 系统 错误码枚举类
*
* 003 activiti
* 001 oa
* activiti 系统使用 1-003-000-000
*/
public interface OaErrorCodeConstants {
ErrorCode LEAVE_NOT_EXISTS = new ErrorCode(1003001001, "请假申请不存在");
}

View File

@ -0,0 +1,14 @@
package cn.iocoder.yudao.adminserver.modules.activiti.enums.form;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
/**
* activiti 系统 错误码枚举类
*
* 003 activiti
* 001 oa
* activiti 系统使用 1-003-000-000
*/
public interface WfFormErrorCodeConstants {
ErrorCode FORM_NOT_EXISTS = new ErrorCode(1003001002, "动态表单不存在");
}

View File

@ -0,0 +1,2 @@
// TODO @芋艿思考下 activitioa 的定位边界模块的拆分
package cn.iocoder.yudao.adminserver.modules.activiti;

View File

@ -0,0 +1,62 @@
package cn.iocoder.yudao.adminserver.modules.activiti.service.config;
import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysPostService;
import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService;
import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import org.activiti.api.runtime.shared.identity.UserGroupManager;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
import static java.util.Collections.singleton;
@Service
public class UserGroupManagerService implements UserGroupManager {
@Resource
private UserDetailsService userDetailsService;
@Resource
private SysUserService userService;
@Resource
private SysPostService sysPostService;
/**
* 暂时使用岗位来代替
* @param userId
* @return
*/
@Override
public List<String> getUserGroups(String userId) {
// final LoginUser loginUser = (LoginUser) userDetailsService.loadUserByUsername(userId);
// final Long id = loginUser.getId();
final SysUserDO user = userService.getUserByUsername(userId);
return sysPostService.getPosts(user.getPostIds()).stream().map(post -> post.getCode()).collect(Collectors.toList());
}
@Override
public List<String> getUserRoles(String userId) {
return Arrays.asList("ROLE_ACTIVITI_USER");
}
@Override
public List<String> getGroups() {
throw new UnsupportedOperationException("getGroups is now un supported");
}
@Override
public List<String> getUsers() {
throw new UnsupportedOperationException("getGroups is now un supported");
}
}

View File

@ -0,0 +1,31 @@
package cn.iocoder.yudao.adminserver.modules.activiti.service.config;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import org.activiti.api.runtime.shared.security.PrincipalGroupsProvider;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import java.security.Principal;
import java.util.Collections;
import java.util.List;
@Service
public class UserGroupsProvider implements PrincipalGroupsProvider {
@Override
public List<String> getGroups(Principal principal) {
if(principal instanceof Authentication){
Authentication authentication = (Authentication) principal;
final Object user = authentication.getPrincipal();
if( user instanceof LoginUser){
return ((LoginUser) user).getGroups();
}else{
return Collections.emptyList();
}
}else{
return Collections.emptyList();
}
}
}

View File

@ -0,0 +1,75 @@
package cn.iocoder.yudao.adminserver.modules.activiti.service.form;
import cn.iocoder.yudao.adminserver.modules.activiti.controller.form.vo.WfFormCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.activiti.controller.form.vo.WfFormExportReqVO;
import cn.iocoder.yudao.adminserver.modules.activiti.controller.form.vo.WfFormPageReqVO;
import cn.iocoder.yudao.adminserver.modules.activiti.controller.form.vo.WfFormUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.activiti.dal.dataobject.form.WfForm;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import java.util.*;
import javax.validation.*;
/**
* 动态表单 Service 接口
*
* TODO @风里雾里
*/
public interface WfFormService {
/**
* 创建动态表单
*
* @param createReqVO 创建信息
* @return 编号
*/
Long createForm(@Valid WfFormCreateReqVO createReqVO);
/**
* 更新动态表单
*
* @param updateReqVO 更新信息
*/
void updateForm(@Valid WfFormUpdateReqVO updateReqVO);
/**
* 删除动态表单
*
* @param id 编号
*/
void deleteForm(Long id);
/**
* 获得动态表单
*
* @param id 编号
* @return 动态表单
*/
WfForm getForm(Long id);
/**
* 获得动态表单列表
*
* @param ids 编号
* @return 动态表单列表
*/
List<WfForm> getFormList(Collection<Long> ids);
/**
* 获得动态表单分页
*
* @param pageReqVO 分页查询
* @return 动态表单分页
*/
PageResult<WfForm> getFormPage(WfFormPageReqVO pageReqVO);
/**
* 获得动态表单列表, 用于 Excel 导出
*
* @param exportReqVO 查询条件
* @return 动态表单列表
*/
List<WfForm> getFormList(WfFormExportReqVO exportReqVO);
}

View File

@ -0,0 +1,86 @@
package cn.iocoder.yudao.adminserver.modules.activiti.service.form.impl;
import cn.iocoder.yudao.adminserver.modules.activiti.controller.form.vo.WfFormCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.activiti.controller.form.vo.WfFormExportReqVO;
import cn.iocoder.yudao.adminserver.modules.activiti.controller.form.vo.WfFormPageReqVO;
import cn.iocoder.yudao.adminserver.modules.activiti.controller.form.vo.WfFormUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.activiti.convert.form.WfFormConvert;
import cn.iocoder.yudao.adminserver.modules.activiti.dal.dataobject.form.WfForm;
import cn.iocoder.yudao.adminserver.modules.activiti.dal.mysql.form.WfFormMapper;
import cn.iocoder.yudao.adminserver.modules.activiti.service.form.WfFormService;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
import static cn.iocoder.yudao.adminserver.modules.activiti.enums.form.WfFormErrorCodeConstants.FORM_NOT_EXISTS;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
/**
* 动态表单 Service 实现类
*
* TODO @风里雾里
*/
@Service
@Validated
public class WfFormServiceImpl implements WfFormService {
@Resource
private WfFormMapper formMapper;
@Override
public Long createForm(WfFormCreateReqVO createReqVO) {
// 插入
WfForm form = WfFormConvert.INSTANCE.convert(createReqVO);
formMapper.insert(form);
// 返回
return form.getId();
}
@Override
public void updateForm(WfFormUpdateReqVO updateReqVO) {
// 校验存在
this.validateFormExists(updateReqVO.getId());
// 更新
WfForm updateObj = WfFormConvert.INSTANCE.convert(updateReqVO);
formMapper.updateById(updateObj);
}
@Override
public void deleteForm(Long id) {
// 校验存在
this.validateFormExists(id);
// 删除
formMapper.deleteById(id);
}
private void validateFormExists(Long id) {
if (formMapper.selectById(id) == null) {
throw exception(FORM_NOT_EXISTS);
}
}
@Override
public WfForm getForm(Long id) {
return formMapper.selectById(id);
}
@Override
public List<WfForm> getFormList(Collection<Long> ids) {
return formMapper.selectBatchIds(ids);
}
@Override
public PageResult<WfForm> getFormPage(WfFormPageReqVO pageReqVO) {
return formMapper.selectPage(pageReqVO);
}
@Override
public List<WfForm> getFormList(WfFormExportReqVO exportReqVO) {
return formMapper.selectList(exportReqVO);
}
}

View File

@ -0,0 +1,76 @@
package cn.iocoder.yudao.adminserver.modules.activiti.service.oa;
import cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo.OaLeaveCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo.OaLeaveExportReqVO;
import cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo.OaLeavePageReqVO;
import cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo.OaLeaveUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.activiti.dal.dataobject.oa.OaLeaveDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import javax.validation.Valid;
import java.util.Collection;
import java.util.List;
/**
* 请假申请 Service 接口
*
* @author 芋艿
*/
public interface OaLeaveService {
/**
* 创建请假申请
*
* @param createReqVO 创建信息
* @return 编号
*/
Long createLeave(@Valid OaLeaveCreateReqVO createReqVO);
/**
* 更新请假申请
*
* @param updateReqVO 更新信息
*/
void updateLeave(@Valid OaLeaveUpdateReqVO updateReqVO);
/**
* 删除请假申请
*
* @param id 编号
*/
void deleteLeave(Long id);
/**
* 获得请假申请
*
* @param id 编号
* @return 请假申请
*/
OaLeaveDO getLeave(Long id);
/**
* 获得请假申请列表
*
* @param ids 编号
* @return 请假申请列表
*/
List<OaLeaveDO> getLeaveList(Collection<Long> ids);
/**
* 获得请假申请分页
*
* @param pageReqVO 分页查询
* @return 请假申请分页
*/
PageResult<OaLeaveDO> getLeavePage(OaLeavePageReqVO pageReqVO);
/**
* 获得请假申请列表, 用于 Excel 导出
*
* @param exportReqVO 查询条件
* @return 请假申请列表
*/
List<OaLeaveDO> getLeaveList(OaLeaveExportReqVO exportReqVO);
}

View File

@ -0,0 +1,43 @@
package cn.iocoder.yudao.adminserver.modules.activiti.service.oa;
import cn.iocoder.yudao.adminserver.modules.activiti.dal.dataobject.oa.OaLeaveDO;
import cn.iocoder.yudao.adminserver.modules.activiti.dal.mysql.oa.OaLeaveMapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.ExecutionListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
@Component
public class ReportBackEndProcessor implements ExecutionListener {
@Resource
private OaLeaveMapper leaveMapper;
// @Override
// @Transactional(rollbackFor = Exception.class)
// public void notify(DelegateTask delegateTask) {
// final String businessKey = delegateTask.getExecution().getProcessInstanceBusinessKey();
// UpdateWrapper<OaLeaveDO> updateWrapper = new UpdateWrapper<>();
// updateWrapper.eq("id", Long.valueOf(businessKey));
// OaLeaveDO updateDo = new OaLeaveDO();
// updateDo.setStatus(2);
// leaveMapper.update(updateDo, updateWrapper);
// }
@Override
@Transactional(rollbackFor = Exception.class)
public void notify(DelegateExecution delegateExecution) {
final String businessKey = delegateExecution.getProcessInstanceBusinessKey();
// TODO @jsonservice 不要出现 dao 的元素例如说 UpdateWrapper这里我们可以调用 updateById 方法
UpdateWrapper<OaLeaveDO> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("id", Long.valueOf(businessKey));
OaLeaveDO updateDo = new OaLeaveDO();
updateDo.setStatus(2); // TODO @jsonstatus 要枚举起来不要出现 magic number
leaveMapper.update(updateDo, updateWrapper);
}
}

View File

@ -0,0 +1,141 @@
package cn.iocoder.yudao.adminserver.modules.activiti.service.oa.impl;
import cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo.OaLeaveCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo.OaLeaveExportReqVO;
import cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo.OaLeavePageReqVO;
import cn.iocoder.yudao.adminserver.modules.activiti.controller.oa.vo.OaLeaveUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.activiti.convert.oa.OaLeaveConvert;
import cn.iocoder.yudao.adminserver.modules.activiti.dal.dataobject.oa.OaLeaveDO;
import cn.iocoder.yudao.adminserver.modules.activiti.dal.mysql.oa.OaLeaveMapper;
import cn.iocoder.yudao.adminserver.modules.activiti.service.oa.OaLeaveService;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import org.activiti.api.task.model.Task;
import org.activiti.api.task.model.builders.TaskPayloadBuilder;
import org.activiti.api.task.runtime.TaskRuntime;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.runtime.ProcessInstance;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static cn.iocoder.yudao.adminserver.modules.activiti.enums.OaErrorCodeConstants.LEAVE_NOT_EXISTS;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
/**
* 请假申请 Service 实现类
*
* @author 芋艿
*/
@Service
@Validated
public class OaLeaveServiceImpl implements OaLeaveService {
@Resource
private OaLeaveMapper leaveMapper;
@Resource
private RuntimeService runtimeService;
@Resource
private org.activiti.engine.TaskService activitiTaskService;
@Resource
private TaskRuntime taskRuntime;
@Override
@Transactional(rollbackFor = Exception.class)
public Long createLeave(OaLeaveCreateReqVO createReqVO) {
// 插入 OA 请假单
OaLeaveDO leave = OaLeaveConvert.INSTANCE.convert(createReqVO);
leave.setStatus(1);
leave.setUserId(SecurityFrameworkUtils.getLoginUser().getUsername());
leaveMapper.insert(leave);
// 创建工作流
Map<String, Object> variables = new HashMap<>();
// 如何得到部门领导人暂时写死
variables.put("deptLeader", "admin"); // TODO @芋艿需要部门的负责人
Long id = leave.getId();
String businessKey = String.valueOf(id);
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(createReqVO.getProcessKey(), businessKey, variables);
String processInstanceId = processInstance.getProcessInstanceId();
// TODO @jsonservice 不要出现 dao 的元素例如说 UpdateWrapper这里我们可以调用 updateById 方法
// 将工作流的编号更新到 OA 请假单中
UpdateWrapper<OaLeaveDO> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("id", id);
OaLeaveDO updateDo = new OaLeaveDO();
updateDo.setProcessInstanceId(processInstanceId);
leaveMapper.update(updateDo, updateWrapper);
return id;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateLeave(OaLeaveUpdateReqVO updateReqVO) {
// 校验存在
this.validateLeaveExists(updateReqVO.getId());
final Task task = taskRuntime.task(updateReqVO.getTaskId());
activitiTaskService.addComment(task.getId(), task.getProcessInstanceId(), updateReqVO.getComment());
Map<String, Object> variables = updateReqVO.getVariables();
//如何得到部门领导人 暂时写死
variables.put("deptLeader", "admin");
taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(task.getId())
.withVariables(variables)
.build());
// TODO @jason不需要加 final 虽然是不变但是代码比较少这么去写
final Object reApply = variables.get("reApply");
// TODO @jason直接使用 Objects.equals(reApply, true) 就可以
if((reApply instanceof Boolean) && (Boolean)reApply){
// 更新 表单
OaLeaveDO updateObj = OaLeaveConvert.INSTANCE.convert(updateReqVO);
leaveMapper.updateById(updateObj);
}
}
@Override
public void deleteLeave(Long id) {
// 校验存在
this.validateLeaveExists(id);
// 删除
leaveMapper.deleteById(id);
// TODO @jason需要调用 runtimeService delete 方法删除
}
private void validateLeaveExists(Long id) {
if (leaveMapper.selectById(id) == null) {
throw exception(LEAVE_NOT_EXISTS);
}
}
@Override
public OaLeaveDO getLeave(Long id) {
return leaveMapper.selectById(id);
}
@Override
public List<OaLeaveDO> getLeaveList(Collection<Long> ids) {
return leaveMapper.selectBatchIds(ids);
}
@Override
public PageResult<OaLeaveDO> getLeavePage(OaLeavePageReqVO pageReqVO) {
return leaveMapper.selectPage(pageReqVO);
}
@Override
public List<OaLeaveDO> getLeaveList(OaLeaveExportReqVO exportReqVO) {
return leaveMapper.selectList(exportReqVO);
}
}

View File

@ -0,0 +1,29 @@
package cn.iocoder.yudao.adminserver.modules.activiti.service.process;
import org.springframework.web.multipart.MultipartFile;
/**
* 流程基础管理
*
* @author ZJQ
* @date 2021/9/5 21:00
*/
public interface ProcessService {
/**
* 上传流程文件进行流程模型部署
* @param multipartFile 上传文件
*/
void deployProcess(MultipartFile multipartFile);
/**
* 激活或者挂起流程模型实体
* @param processDefinitionId 流程模型实体id
* @param type 类型
* @return 状态
*/
String setActivOrHang(String processDefinitionId,String type);
}

View File

@ -0,0 +1,109 @@
package cn.iocoder.yudao.adminserver.modules.activiti.service.process.impl;
import cn.iocoder.yudao.adminserver.modules.activiti.service.process.ProcessService;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.apache.commons.io.FilenameUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.zip.ZipInputStream;
import static cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants.FILE_UPLOAD_FAILED;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
/**
* 流程基础管理
*
* @author ZJQ
* @date 2021/9/5 21:04
*/
@Service
@Slf4j
public class ProcessServiceImpl implements ProcessService {
private static final String BPMN20_XML = "bpmn20.xml";
@Resource
private RepositoryService repositoryService;
/**
* 上传流程文件进行流程部署
* @param multipartFile 上传文件
*/
@Override
public void deployProcess(MultipartFile multipartFile) {
String fileName = multipartFile.getOriginalFilename();
try (InputStream inputStream = multipartFile.getInputStream()){
Deployment deployment = getDeplymentByType(inputStream,fileName);
//获取部署成功的流程模型
List<ProcessDefinition> processDefinitions = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).list();
processDefinitions.forEach((processDefinition)->{
//设置线上部署流程模型名字
String proDefId = processDefinition.getId();
repositoryService.setProcessDefinitionCategory(proDefId,fileName);
log.info("流程文件部署成功流程ID="+proDefId);
});
} catch (IOException e) {
log.error("流程部署出现异常"+e);
}
}
/**
* 激活或者挂起流程模型实体
* @param processDefinitionId 流程模型实体id
* @param type 类型
* @return 提示
*/
@Override
public String setActivOrHang(String processDefinitionId, String type) {
String result = "无操作";
switch (type){
case "active":
repositoryService.activateProcessDefinitionById(processDefinitionId,true,null);
result = "已激活ID为【"+processDefinitionId+"】的流程模型实例";
break;
case "suspend":
repositoryService.suspendProcessDefinitionById(processDefinitionId,true,null);
result = "已挂起ID为【"+processDefinitionId+"】的流程模型实例";
break;
default:
break;
}
return result;
}
/**
* 根据上传文件类型对应实现不同方式的流程部署
* @param inputStream 文件输入流
* @param fileName 文件名
* @return 文件部署流程
*/
public Deployment getDeplymentByType(InputStream inputStream,String fileName){
Deployment deployment;
String type = FilenameUtils.getExtension(fileName);
switch (type){
case "bpmn":
String baseName = FilenameUtils.getBaseName(fileName);
deployment = repositoryService.createDeployment().addInputStream(baseName+"."+BPMN20_XML,inputStream).deploy();
break;
case "png":
deployment = repositoryService.createDeployment().addInputStream(fileName,inputStream).deploy();
break;
case "zip":
case "bar":
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
deployment = repositoryService.createDeployment().addZipInputStream(zipInputStream).deploy();
break;
default:
throw exception(FILE_UPLOAD_FAILED);
}
return deployment;
}
}

View File

@ -0,0 +1,26 @@
package cn.iocoder.yudao.adminserver.modules.activiti.service.workflow;
import cn.iocoder.yudao.adminserver.modules.activiti.controller.workflow.vo.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import java.util.List;
// TODO @芋艿前缀注释
public interface TaskService {
PageResult<TodoTaskRespVO> getTodoTaskPage(TodoTaskPageReqVO pageReqVO);
void claimTask(String taskId);
void getTaskHistory(String taskId);
void completeTask(TaskReqVO taskReq);
// void flowImage(String taskId, HttpServletResponse response);
TaskHandleVO getTaskSteps(TaskQueryReqVO taskQuery);
List<TaskStepVO> getHistorySteps(String processInstanceId);
TodoTaskRespVO getTaskFormKey(TaskQueryReqVO taskQuery);
}

View File

@ -0,0 +1,266 @@
package cn.iocoder.yudao.adminserver.modules.activiti.service.workflow.impl;
import cn.iocoder.yudao.adminserver.modules.activiti.controller.workflow.vo.*;
import cn.iocoder.yudao.adminserver.modules.activiti.dal.mysql.oa.OaLeaveMapper;
import cn.iocoder.yudao.adminserver.modules.activiti.service.workflow.TaskService;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import com.google.common.collect.ImmutableMap;
import org.activiti.api.runtime.shared.query.Page;
import org.activiti.api.runtime.shared.query.Pageable;
import org.activiti.api.task.model.Task;
import org.activiti.api.task.model.builders.ClaimTaskPayloadBuilder;
import org.activiti.api.task.model.builders.TaskPayloadBuilder;
import org.activiti.api.task.runtime.TaskRuntime;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.task.Comment;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
@Service
public class TaskServiceImpl implements TaskService {
@Resource
private TaskRuntime taskRuntime;
@Resource
private org.activiti.engine.TaskService activitiTaskService;
@Resource
private HistoryService historyService;
@Resource
private RepositoryService repositoryService;
@Resource
private OaLeaveMapper leaveMapper;
private static Map<String,String> taskVariable = ImmutableMap.<String,String>builder()
.put("deptLeaderVerify","deptLeaderApproved")
.put("hrVerify","hrApproved")
.build();
public TaskServiceImpl() {
}
@Override
public PageResult<TodoTaskRespVO> getTodoTaskPage(TodoTaskPageReqVO pageReqVO) {
final LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
// TODO @jason封装一个方法用于转换成 activiti 的分页对象
final Pageable pageable = Pageable.of((pageReqVO.getPageNo() - 1) * pageReqVO.getPageSize(), pageReqVO.getPageSize());
Page<Task> pageTasks = taskRuntime.tasks(pageable);
// TODO @jasonconvert 里转换
List<Task> tasks = pageTasks.getContent();
int totalItems = pageTasks.getTotalItems();
final List<TodoTaskRespVO> respVOList = tasks.stream().map(task -> {
TodoTaskRespVO respVO = new TodoTaskRespVO();
respVO.setId(task.getId());
final ProcessDefinition definition = repositoryService.getProcessDefinition(task.getProcessDefinitionId());
respVO.setProcessName(definition.getName());
respVO.setProcessKey(definition.getKey());
respVO.setBusinessKey(task.getBusinessKey());
respVO.setStatus(task.getAssignee() == null ? 1 : 2);
return respVO;
}).collect(Collectors.toList());
// TODO @jason要注意泛型哈
return new PageResult(respVOList, Long.valueOf(totalItems)); // TODO @jason(long) 转换即可
}
@Override
public void claimTask(String taskId) {
taskRuntime.claim(new ClaimTaskPayloadBuilder()
.withTaskId(taskId)
.withAssignee(SecurityFrameworkUtils.getLoginUser().getUsername())
.build());
}
@Override
public void getTaskHistory(String taskId) {
final List<HistoricProcessInstance> list = historyService.createHistoricProcessInstanceQuery().
processInstanceId("8e2801fc-1a38-11ec-98ce-74867a13730f").list();
}
// TODO @jason一个方法里会有多个方法的调用最好写下对应的注释这样容易理解
@Override
@Transactional
public void completeTask(TaskReqVO taskReq) {
final Task task = taskRuntime.task(taskReq.getTaskId());
final Map<String, Object> variables = taskReq.getVariables();
activitiTaskService.addComment(taskReq.getTaskId(), task.getProcessInstanceId(), taskReq.getComment());
taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(taskReq.getTaskId())
.withVariables(taskReq.getVariables())
.build());
// if(variables.containsValue(Boolean.FALSE)){
// final String businessKey = task.getBusinessKey();
// UpdateWrapper<OaLeaveDO> updateWrapper = new UpdateWrapper<>();
// updateWrapper.eq("id", Long.valueOf(businessKey));
// OaLeaveDO updateDo = new OaLeaveDO();
// updateDo.setStatus(2);
// leaveMapper.update(updateDo, updateWrapper);
// }
}
// @Override
// public void flowImage(String taskId, HttpServletResponse response) {
//
// final Task task = taskRuntime.task(taskId);
// BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
// final Process process = bpmnModel.getMainProcess();
// ProcessDefinitionEntity processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult();
// List<String> activeActivityIds = runtimeService.getActiveActivityIds(executionId);
// List<String> highLightedFlows = getHighLightedFlows(processDefinition, processInstance.getId());
// ProcessDiagramGenerator diagramGenerator = processEngineConfiguration.getProcessDiagramGenerator();
// InputStream imageStream =diagramGenerator.generateDiagram(bpmnModel, "png", activeActivityIds, highLightedFlows);
//
// // 输出资源内容到相应对象
// byte[] b = new byte[1024];
// int len;
// while ((len = imageStream.read(b, 0, 1024)) != -1) {
// response.getOutputStream().write(b, 0, len);
// }
// }
@Override
public TaskHandleVO getTaskSteps(TaskQueryReqVO taskQuery) {
TaskHandleVO handleVO = new TaskHandleVO();
// String processKey = taskQuery.getProcessKey();
// if ("leave".equals(processKey)) {
// String businessKey = taskQuery.getBusinessKey();
// final OaLeaveDO leave = leaveMapper.selectById(Long.valueOf(businessKey));
// handleVO.setFormObject( OaLeaveConvert.INSTANCE.convert(leave));
// }
//
// final String taskDefKey = task.getTaskDefinitionKey();
// final String variableName = Optional.ofNullable(taskVariable.get(taskDefKey)).orElse("");
// handleVO.setTaskVariable(variableName);
final Task task = taskRuntime.task(taskQuery.getTaskId());
List<TaskStepVO> steps = getTaskSteps(task.getProcessInstanceId());
handleVO.setHistoryTask(steps);
return handleVO;
}
private List<TaskStepVO> getTaskSteps(String processInstanceId) {
// 获得已完成的活动
List<HistoricActivityInstance> finished = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(processInstanceId)
.activityType("userTask")
.finished()
.orderByHistoricActivityInstanceStartTime().asc().list();
// 获得对应的步骤
List<TaskStepVO> steps = new ArrayList<>();
finished.forEach(instance -> {
// TODO @jason放到 convert
TaskStepVO step = new TaskStepVO();
step.setStepName(instance.getActivityName());
step.setStartTime(instance.getStartTime());
step.setEndTime(instance.getEndTime());
step.setAssignee(instance.getAssignee());
step.setStatus(1);
// TODO @jason一般判数组为空使用 CollUtil.isEmpty 会好点哈另外null 时候不用填写 "" 的哈
List<Comment> comments = activitiTaskService.getTaskComments(instance.getTaskId());
if (comments.size() > 0) {
step.setComment(comments.get(0).getFullMessage());
} else {
step.setComment("");
}
steps.add(step);
});
// 获得未完成的活动
List<HistoricActivityInstance> unfinished = historyService
.createHistoricActivityInstanceQuery()
.processInstanceId(processInstanceId)
.activityType("userTask")
.unfinished().list();
// 获得对应的步骤
// TODO @json其实已完成和未完成它们的 convert 的逻辑是一致的
for (HistoricActivityInstance instance : unfinished) {
TaskStepVO step = new TaskStepVO();
step.setStepName(instance.getActivityName());
step.setStartTime(instance.getStartTime());
step.setEndTime(instance.getEndTime());
step.setAssignee(Optional.ofNullable(instance.getAssignee()).orElse(""));
step.setComment("");
step.setStatus(0);
steps.add(step);
}
return steps;
}
@Override
public List<TaskStepVO> getHistorySteps(String processInstanceId) {
return getTaskSteps(processInstanceId);
}
@Override
public TodoTaskRespVO getTaskFormKey(TaskQueryReqVO taskQuery) {
final Task task = taskRuntime.task(taskQuery.getTaskId());
// 转换结果
TodoTaskRespVO respVO = new TodoTaskRespVO();
respVO.setFormKey(task.getFormKey());
respVO.setBusinessKey(task.getBusinessKey());
respVO.setId(task.getId());
return respVO;
}
// private List<String> getHighLightedFlows(ProcessDefinitionEntity processDefinition, String processInstanceId) {
//
// List<String> highLightedFlows = new ArrayList<String>();
// List<HistoricActivityInstance> historicActivityInstances = historyService
// .createHistoricActivityInstanceQuery()
// .processInstanceId(processInstanceId)
// .orderByHistoricActivityInstanceStartTime().asc().list();
//
// List<String> historicActivityInstanceList = new ArrayList<String>();
// for (HistoricActivityInstance hai : historicActivityInstances) {
// historicActivityInstanceList.add(hai.getActivityId());
// }
// // add current activities to list
// List<String> highLightedActivities = runtimeService.getActiveActivityIds(processInstanceId);
// historicActivityInstanceList.addAll(highLightedActivities);
// activities and their sequence-flows
// for (ActivityImpl activity : processDefinition.getActivities()) {
// int index = historicActivityInstanceList.indexOf(activity.getId());
//
// if (index >= 0 && index + 1 < historicActivityInstanceList.size()) {
// List<PvmTransition> pvmTransitionList = activity
// .getOutgoingTransitions();
// for (PvmTransition pvmTransition : pvmTransitionList) {
// String destinationFlowId = pvmTransition.getDestination().getId();
// if (destinationFlowId.equals(historicActivityInstanceList.get(index + 1))) {
// highLightedFlows.add(pvmTransition.getId());
// }
// }
// }
// }
// return highLightedFlows;
// }
}

View File

@ -1,13 +1,13 @@
package cn.iocoder.yudao.adminserver.modules.infra.mq.message.config;
import cn.iocoder.yudao.framework.mq.core.pubsub.ChannelMessage;
import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;
import lombok.Data;
/**
* 配置数据刷新 Message
*/
@Data
public class InfConfigRefreshMessage implements ChannelMessage {
public class InfConfigRefreshMessage extends AbstractChannelMessage {
@Override
public String getChannel() {

View File

@ -1,8 +1,7 @@
package cn.iocoder.yudao.adminserver.modules.infra.mq.producer.config;
import cn.iocoder.yudao.adminserver.modules.infra.mq.message.config.InfConfigRefreshMessage;
import cn.iocoder.yudao.framework.mq.core.util.RedisMessageUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@ -14,14 +13,14 @@ import javax.annotation.Resource;
public class InfConfigProducer {
@Resource
private StringRedisTemplate stringRedisTemplate;
private RedisMQTemplate redisMQTemplate;
/**
* 发送 {@link InfConfigRefreshMessage} 消息
*/
public void sendConfigRefreshMessage() {
InfConfigRefreshMessage message = new InfConfigRefreshMessage();
RedisMessageUtils.sendChannelMessage(stringRedisTemplate, message);
redisMQTemplate.send(message);
}
}

View File

@ -1,21 +1,25 @@
### 请求 /login 接口 => 成功
POST {{baseUrl}}/login
Content-Type: application/json
tenant-id: 1
{
"username": "admin",
"password": "admin123",
"uuid": "9b2ffbc1-7425-4155-9894-9d5c08541d62",
"uuid": "3acd87a09a4f48fb9118333780e94883",
"code": "1024"
}
### 请求 /get-permission-info 接口 => 成功
GET {{baseUrl}}/get-permission-info
Authorization: Bearer {{token}}
tenant-id: 1
### 请求 /list-menus 接口 => 成功
GET {{baseUrl}}/list-menus
Authorization: Bearer {{token}}
#Authorization: Bearer a6aa7714a2e44c95aaa8a2c5adc2a67a
tenant-id: 1
### 请求 /druid/xxx 接口 => 失败 TODO 临时测试
GET http://127.0.0.1:8080/druid/123

View File

@ -60,7 +60,7 @@ public class SysDictTypeController {
@ApiOperation("/获得字典类型的分页列表")
@GetMapping("/page")
@PreAuthorize("@ss.hasPermission('system:dict:quey')")
@PreAuthorize("@ss.hasPermission('system:dict:query')")
public CommonResult<PageResult<SysDictTypeRespVO>> pageDictTypes(@Valid SysDictTypePageReqVO reqVO) {
return success(SysDictTypeConvert.INSTANCE.convertPage(dictTypeService.getDictTypePage(reqVO)));
}
@ -68,7 +68,7 @@ public class SysDictTypeController {
@ApiOperation("/查询字典类型详细")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@GetMapping(value = "/get")
@PreAuthorize("@ss.hasPermission('system:dict:quey')")
@PreAuthorize("@ss.hasPermission('system:dict:query')")
public CommonResult<SysDictTypeRespVO> getDictType(@RequestParam("id") Long id) {
return success(SysDictTypeConvert.INSTANCE.convert(dictTypeService.getDictType(id)));
}
@ -83,7 +83,7 @@ public class SysDictTypeController {
@ApiOperation("导出数据类型")
@GetMapping("/export")
@PreAuthorize("@ss.hasPermission('system:dict:quey')")
@PreAuthorize("@ss.hasPermission('system:dict:query')")
@OperateLog(type = EXPORT)
public void export(HttpServletResponse response, @Valid SysDictTypeExportReqVO reqVO) throws IOException {
List<SysDictTypeDO> list = dictTypeService.getDictTypeList(reqVO);

View File

@ -56,7 +56,7 @@ public class SysNoticeController {
@GetMapping("/page")
@ApiOperation("获取通知公告列表")
@PreAuthorize("@ss.hasPermission('system:notice:quey')")
@PreAuthorize("@ss.hasPermission('system:notice:query')")
public CommonResult<PageResult<SysNoticeRespVO>> pageNotices(@Validated SysNoticePageReqVO reqVO) {
return success(SysNoticeConvert.INSTANCE.convertPage(noticeService.pageNotices(reqVO)));
}
@ -64,7 +64,7 @@ public class SysNoticeController {
@GetMapping("/get")
@ApiOperation("获得通知公告")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('system:notice:quey')")
@PreAuthorize("@ss.hasPermission('system:notice:query')")
public CommonResult<SysNoticeRespVO> getNotice(@RequestParam("id") Long id) {
return success(SysNoticeConvert.INSTANCE.convert(noticeService.getNotice(id)));
}

View File

@ -0,0 +1,106 @@
package cn.iocoder.yudao.adminserver.modules.system.controller.tenant;
import cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo.*;
import cn.iocoder.yudao.adminserver.modules.system.convert.tenant.SysTenantConvert;
import cn.iocoder.yudao.adminserver.modules.system.service.tenant.SysTenantService;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.tenant.SysTenantDO;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Api(tags = "租户")
@RestController
@RequestMapping("/system/tenant")
public class SysTenantController {
@Resource
private SysTenantService tenantService;
@GetMapping("/get-id-by-name")
@ApiOperation(value = "使用租户名,获得租户编号", notes = "登录界面,根据用户的租户名,获得租户编号")
@ApiImplicitParam(name = "name", value = "租户名", required = true, example = "芋道源码", dataTypeClass = Long.class)
public CommonResult<Long> getTenantIdByName(@RequestParam("name") String name) {
SysTenantDO tenantDO = tenantService.getTenantByName(name);
return success(tenantDO != null ? tenantDO.getId() : null);
}
@PostMapping("/create")
@ApiOperation("创建租户")
@PreAuthorize("@ss.hasPermission('system:tenant:create')")
public CommonResult<Long> createTenant(@Valid @RequestBody SysTenantCreateReqVO createReqVO) {
return success(tenantService.createTenant(createReqVO));
}
@PutMapping("/update")
@ApiOperation("更新租户")
@PreAuthorize("@ss.hasPermission('system:tenant:update')")
public CommonResult<Boolean> updateTenant(@Valid @RequestBody SysTenantUpdateReqVO updateReqVO) {
tenantService.updateTenant(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@ApiOperation("删除租户")
@ApiImplicitParam(name = "id", value = "编号", required = true)
@PreAuthorize("@ss.hasPermission('system:tenant:delete')")
public CommonResult<Boolean> deleteTenant(@RequestParam("id") Long id) {
tenantService.deleteTenant(id);
return success(true);
}
@GetMapping("/get")
@ApiOperation("获得租户")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('system:tenant:query')")
public CommonResult<SysTenantRespVO> getTenant(@RequestParam("id") Long id) {
SysTenantDO tenant = tenantService.getTenant(id);
return success(SysTenantConvert.INSTANCE.convert(tenant));
}
@GetMapping("/list")
@ApiOperation("获得租户列表")
@ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class)
@PreAuthorize("@ss.hasPermission('system:tenant:query')")
public CommonResult<List<SysTenantRespVO>> getTenantList(@RequestParam("ids") Collection<Long> ids) {
List<SysTenantDO> list = tenantService.getTenantList(ids);
return success(SysTenantConvert.INSTANCE.convertList(list));
}
@GetMapping("/page")
@ApiOperation("获得租户分页")
@PreAuthorize("@ss.hasPermission('system:tenant:query')")
public CommonResult<PageResult<SysTenantRespVO>> getTenantPage(@Valid SysTenantPageReqVO pageVO) {
PageResult<SysTenantDO> pageResult = tenantService.getTenantPage(pageVO);
return success(SysTenantConvert.INSTANCE.convertPage(pageResult));
}
@GetMapping("/export-excel")
@ApiOperation("导出租户 Excel")
@PreAuthorize("@ss.hasPermission('system:tenant:export')")
@OperateLog(type = EXPORT)
public void exportTenantExcel(@Valid SysTenantExportReqVO exportReqVO,
HttpServletResponse response) throws IOException {
List<SysTenantDO> list = tenantService.getTenantList(exportReqVO);
// 导出 Excel
List<SysTenantExcelVO> datas = SysTenantConvert.INSTANCE.convertList02(list);
ExcelUtils.write(response, "租户.xls", "数据", SysTenantExcelVO.class, datas);
}
}

View File

@ -0,0 +1,30 @@
package cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import javax.validation.constraints.*;
/**
* 租户 Base VO提供给添加修改详细的子 VO 使用
* 如果子 VO 存在差异的字段请不要添加到这里影响 Swagger 文档生成
*/
@Data
public class SysTenantBaseVO {
@ApiModelProperty(value = "租户名", required = true, example = "芋道")
@NotNull(message = "租户名不能为空")
private String name;
@ApiModelProperty(value = "联系人", required = true, example = "芋艿")
@NotNull(message = "联系人不能为空")
private String contactName;
@ApiModelProperty(value = "联系手机", example = "15601691300")
private String contactMobile;
@ApiModelProperty(value = "租户状态0正常 1停用", required = true, example = "1")
@NotNull(message = "租户状态0正常 1停用不能为空")
private Integer status;
}

View File

@ -0,0 +1,14 @@
package cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import javax.validation.constraints.*;
@ApiModel("租户创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class SysTenantCreateReqVO extends SysTenantBaseVO {
}

View File

@ -0,0 +1,39 @@
package cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import com.alibaba.excel.annotation.ExcelProperty;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
/**
* 租户 Excel VO
*
* @author 芋道源码
*/
@Data
public class SysTenantExcelVO {
@ExcelProperty("租户编号")
private Long id;
@ExcelProperty("租户名")
private String name;
@ExcelProperty("联系人")
private String contactName;
@ExcelProperty("联系手机")
private String contactMobile;
@ExcelProperty(value = "租户状态0正常 1停用", converter = DictConvert.class)
@DictFormat("sys_common_status") // TODO 代码优化建议设置到对应的 XXXDictTypeConstants 枚举类中
private Integer status;
@ExcelProperty("创建时间")
private Date createTime;
}

View File

@ -0,0 +1,36 @@
package cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel(value = "租户 Excel 导出 Request VO", description = "参数和 SysTenantPageReqVO 是一致的")
@Data
public class SysTenantExportReqVO {
@ApiModelProperty(value = "租户名", example = "芋道")
private String name;
@ApiModelProperty(value = "联系人", example = "芋艿")
private String contactName;
@ApiModelProperty(value = "联系手机", example = "15601691300")
private String contactMobile;
@ApiModelProperty(value = "租户状态0正常 1停用", example = "1")
private Integer status;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "开始创建时间")
private Date beginCreateTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "结束创建时间")
private Date endCreateTime;
}

View File

@ -0,0 +1,41 @@
package cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel("租户分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class SysTenantPageReqVO extends PageParam {
@ApiModelProperty(value = "租户名", example = "芋道")
private String name;
@ApiModelProperty(value = "联系人", example = "芋艿")
private String contactName;
@ApiModelProperty(value = "联系手机", example = "15601691300")
private String contactMobile;
@ApiModelProperty(value = "租户状态0正常 1停用", example = "1")
private Integer status;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "开始创建时间")
private Date beginCreateTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "结束创建时间")
private Date endCreateTime;
}

View File

@ -0,0 +1,19 @@
package cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
@ApiModel("租户 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class SysTenantRespVO extends SysTenantBaseVO {
@ApiModelProperty(value = "租户编号", required = true, example = "1024")
private Long id;
@ApiModelProperty(value = "创建时间", required = true)
private Date createTime;
}

View File

@ -0,0 +1,18 @@
package cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import javax.validation.constraints.*;
@ApiModel("租户更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class SysTenantUpdateReqVO extends SysTenantBaseVO {
@ApiModelProperty(value = "租户编号", required = true, example = "1024")
@NotNull(message = "租户编号不能为空")
private Long id;
}

View File

@ -1,3 +1,4 @@
### 请求 /system/user/page 接口 => 没有权限
GET {{baseUrl}}/system/user/page?pageNo=1&pageSize=10
Authorization: Bearer test104 # 使用测试账号
Authorization: Bearer test1 # 使用测试账号
tenant-id: 1

View File

@ -0,0 +1,36 @@
package cn.iocoder.yudao.adminserver.modules.system.convert.tenant;
import cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo.SysTenantCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo.SysTenantExcelVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo.SysTenantRespVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo.SysTenantUpdateReqVO;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.tenant.SysTenantDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
/**
* 租户 Convert
*
* @author 芋道源码
*/
@Mapper
public interface SysTenantConvert {
SysTenantConvert INSTANCE = Mappers.getMapper(SysTenantConvert.class);
SysTenantDO convert(SysTenantCreateReqVO bean);
SysTenantDO convert(SysTenantUpdateReqVO bean);
SysTenantRespVO convert(SysTenantDO bean);
List<SysTenantRespVO> convertList(List<SysTenantDO> list);
PageResult<SysTenantRespVO> convertPage(PageResult<SysTenantDO> page);
List<SysTenantExcelVO> convertList02(List<SysTenantDO> list);
}

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@ -15,7 +15,7 @@ import lombok.EqualsAndHashCode;
@TableName("sys_dept")
@Data
@EqualsAndHashCode(callSuper = true)
public class SysDeptDO extends BaseDO {
public class SysDeptDO extends TenantBaseDO {
/**
* 部门ID

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@ -15,14 +15,13 @@ import lombok.EqualsAndHashCode;
@TableName("sys_post")
@Data
@EqualsAndHashCode(callSuper = true)
public class SysPostDO extends BaseDO {
public class SysPostDO extends TenantBaseDO {
/**
* 岗位序号
*/
@TableId
private Long id;
/**
* 岗位名称
*/

View File

@ -3,7 +3,7 @@ package cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.logger;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
@ -22,7 +22,7 @@ import java.util.Map;
@TableName(value = "sys_operate_log", autoResultMap = true)
@Data
@EqualsAndHashCode(callSuper = true)
public class SysOperateLogDO extends BaseDO {
public class SysOperateLogDO extends TenantBaseDO {
/**
* {@link #javaMethodArgs} 的最大长度

View File

@ -1,8 +1,8 @@
package cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.notice;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.adminserver.modules.system.enums.notice.SysNoticeTypeEnum;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@ -16,7 +16,7 @@ import lombok.EqualsAndHashCode;
@TableName("sys_notice")
@Data
@EqualsAndHashCode(callSuper = true)
public class SysNoticeDO extends BaseDO {
public class SysNoticeDO extends TenantBaseDO {
/**
* 公告ID

View File

@ -24,7 +24,7 @@ public interface SysDeptMapper extends BaseMapperX<SysDeptDO> {
}
default Integer selectCountByParentId(Long parentId) {
return selectCount(new QueryWrapper<SysDeptDO>().eq("parent_id", parentId));
return selectCount("parent_id", parentId);
}
default boolean selectExistsByUpdateTimeAfter(Date maxUpdateTime) {

View File

@ -19,7 +19,7 @@ public interface SysMenuMapper extends BaseMapperX<SysMenuDO> {
}
default Integer selectCountByParentId(Long parentId) {
return selectCount(new QueryWrapper<SysMenuDO>().eq("parent_id", parentId));
return selectCount("parent_id", parentId);
}
default List<SysMenuDO> selectList(SysMenuListReqVO reqVO) {

View File

@ -0,0 +1,44 @@
package cn.iocoder.yudao.adminserver.modules.system.dal.mysql.tenant;
import cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo.SysTenantExportReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo.SysTenantPageReqVO;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.tenant.SysTenantDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* 租户 Mapper
*
* @author 芋道源码
*/
@Mapper
public interface SysTenantMapper extends BaseMapperX<SysTenantDO> {
default PageResult<SysTenantDO> selectPage(SysTenantPageReqVO reqVO) {
return selectPage(reqVO, new QueryWrapperX<SysTenantDO>()
.likeIfPresent("name", reqVO.getName())
.likeIfPresent("contact_name", reqVO.getContactName())
.likeIfPresent("contact_mobile", reqVO.getContactMobile())
.eqIfPresent("status", reqVO.getStatus())
.betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
.orderByDesc("id"));
}
default List<SysTenantDO> selectList(SysTenantExportReqVO reqVO) {
return selectList(new QueryWrapperX<SysTenantDO>()
.likeIfPresent("name", reqVO.getName())
.likeIfPresent("contact_name", reqVO.getContactName())
.likeIfPresent("contact_mobile", reqVO.getContactMobile())
.eqIfPresent("status", reqVO.getStatus())
.betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
.orderByDesc("id"));
}
default SysTenantDO selectByName(String name) {
return selectOne("name", name);
}
}

View File

@ -85,10 +85,12 @@ public interface SysErrorCodeConstants {
ErrorCode SMS_TEMPLATE_NOT_EXISTS = new ErrorCode(1002011000, "短信模板不存在");
ErrorCode SMS_TEMPLATE_CODE_DUPLICATE = new ErrorCode(1002011001, "已经存在编码为【{}】的短信模板");
// ========== 租户模块 1002012000 ==========
ErrorCode TENANT_NOT_EXISTS = new ErrorCode(1002012000, "租户不存在");
// ========== 错误码模块 1002013000 ==========
ErrorCode ERROR_CODE_NOT_EXISTS = new ErrorCode(1002013000, "错误码不存在");
ErrorCode ERROR_CODE_DUPLICATE = new ErrorCode(1002013001, "已经存在编码为【{}】的错误码");
}

View File

@ -12,6 +12,13 @@ import java.time.Duration;
@Data
public class CaptchaProperties {
private static final Boolean ENABLE_DEFAULT = true;
/**
* 是否开启
* 注意这里仅仅是后端 Server 是否校验暂时不控制前端的逻辑
*/
private Boolean enable = ENABLE_DEFAULT;
/**
* 验证码的过期时间
*/

View File

@ -0,0 +1,25 @@
package cn.iocoder.yudao.adminserver.modules.system.framework.datapermission.config;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept.SysDeptDO;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
import cn.iocoder.yudao.framework.datapermission.core.dept.rule.DeptDataPermissionRuleCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* system 模块的数据权限 Configuration
*
* @author 芋道源码
*/
@Configuration
public class SysDataPermissionConfiguration {
@Bean
public DeptDataPermissionRuleCustomizer sysDeptDataPermissionRuleCustomizer() {
return rule -> {
rule.addDeptColumn(SysUserDO.class);
rule.addDeptColumn(SysDeptDO.class, "id");
};
}
}

View File

@ -0,0 +1,4 @@
/**
* system 模块的数据权限配置
*/
package cn.iocoder.yudao.adminserver.modules.system.framework.datapermission;

View File

@ -2,6 +2,7 @@ package cn.iocoder.yudao.adminserver.modules.system.job.auth;
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
import cn.iocoder.yudao.adminserver.modules.system.service.auth.SysUserSessionService;
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@ -13,6 +14,7 @@ import javax.annotation.Resource;
* @author
*/
@Component
@TenantJob
@Slf4j
public class SysUserSessionTimeoutJob implements JobHandler {

View File

@ -1,13 +1,17 @@
package cn.iocoder.yudao.adminserver.modules.system.mq.message.dept;
import cn.iocoder.yudao.framework.mq.core.pubsub.ChannelMessage;
import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 部门数据刷新 Message
*
* @author 芋道源码
*/
@Data
public class SysDeptRefreshMessage implements ChannelMessage {
@EqualsAndHashCode(callSuper = true)
public class SysDeptRefreshMessage extends AbstractChannelMessage {
@Override
public String getChannel() {

View File

@ -1,13 +1,15 @@
package cn.iocoder.yudao.adminserver.modules.system.mq.message.dict;
import cn.iocoder.yudao.framework.mq.core.pubsub.ChannelMessage;
import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 字典数据数据刷新 Message
*/
@Data
public class SysDictDataRefreshMessage implements ChannelMessage {
@EqualsAndHashCode(callSuper = true)
public class SysDictDataRefreshMessage extends AbstractChannelMessage {
@Override
public String getChannel() {

View File

@ -1,7 +1,8 @@
package cn.iocoder.yudao.adminserver.modules.system.mq.message.mail;
import cn.iocoder.yudao.framework.mq.core.stream.StreamMessage;
import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessage;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotNull;
import java.util.Map;
@ -12,7 +13,8 @@ import java.util.Map;
* @author 芋道源码
*/
@Data
public class SysMailSendMessage implements StreamMessage {
@EqualsAndHashCode(callSuper = true)
public class SysMailSendMessage extends AbstractStreamMessage {
/**
* 邮箱地址

View File

@ -1,13 +1,17 @@
package cn.iocoder.yudao.adminserver.modules.system.mq.message.permission;
import cn.iocoder.yudao.framework.mq.core.pubsub.ChannelMessage;
import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 菜单数据刷新 Message
*
* @author 芋道源码
*/
@Data
public class SysMenuRefreshMessage implements ChannelMessage {
@EqualsAndHashCode(callSuper = true)
public class SysMenuRefreshMessage extends AbstractChannelMessage {
@Override
public String getChannel() {

View File

@ -1,13 +1,17 @@
package cn.iocoder.yudao.adminserver.modules.system.mq.message.permission;
import cn.iocoder.yudao.framework.mq.core.pubsub.ChannelMessage;
import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 角色与菜单数据刷新 Message
*
* @author 芋道源码
*/
@Data
public class SysRoleMenuRefreshMessage implements ChannelMessage {
@EqualsAndHashCode(callSuper = true)
public class SysRoleMenuRefreshMessage extends AbstractChannelMessage {
@Override
public String getChannel() {

View File

@ -1,13 +1,17 @@
package cn.iocoder.yudao.adminserver.modules.system.mq.message.permission;
import cn.iocoder.yudao.framework.mq.core.pubsub.ChannelMessage;
import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 角色数据刷新 Message
*
* @author 芋道源码
*/
@Data
public class SysRoleRefreshMessage implements ChannelMessage {
@EqualsAndHashCode(callSuper = true)
public class SysRoleRefreshMessage extends AbstractChannelMessage {
@Override
public String getChannel() {

View File

@ -1,13 +1,17 @@
package cn.iocoder.yudao.adminserver.modules.system.mq.message.sms;
import cn.iocoder.yudao.framework.mq.core.pubsub.ChannelMessage;
import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 短信渠道的数据刷新 Message
*
* @author 芋道源码
*/
@Data
public class SysSmsChannelRefreshMessage implements ChannelMessage {
@EqualsAndHashCode(callSuper = true)
public class SysSmsChannelRefreshMessage extends AbstractChannelMessage {
@Override
public String getChannel() {

View File

@ -1,13 +1,17 @@
package cn.iocoder.yudao.adminserver.modules.system.mq.message.sms;
import cn.iocoder.yudao.framework.mq.core.pubsub.ChannelMessage;
import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 短信模板的数据刷新 Message
*
* @author 芋道源码
*/
@Data
public class SysSmsTemplateRefreshMessage implements ChannelMessage {
@EqualsAndHashCode(callSuper = true)
public class SysSmsTemplateRefreshMessage extends AbstractChannelMessage {
@Override
public String getChannel() {

View File

@ -1,8 +1,7 @@
package cn.iocoder.yudao.adminserver.modules.system.mq.producer.dept;
import cn.iocoder.yudao.framework.mq.core.util.RedisMessageUtils;
import cn.iocoder.yudao.adminserver.modules.system.mq.message.dept.SysDeptRefreshMessage;
import org.springframework.data.redis.core.StringRedisTemplate;
import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@ -14,14 +13,14 @@ import javax.annotation.Resource;
public class SysDeptProducer {
@Resource
private StringRedisTemplate stringRedisTemplate;
private RedisMQTemplate redisMQTemplate;
/**
* 发送 {@link SysDeptRefreshMessage} 消息
*/
public void sendDeptRefreshMessage() {
SysDeptRefreshMessage message = new SysDeptRefreshMessage();
RedisMessageUtils.sendChannelMessage(stringRedisTemplate, message);
redisMQTemplate.send(message);
}
}

View File

@ -1,8 +1,7 @@
package cn.iocoder.yudao.adminserver.modules.system.mq.producer.dict;
import cn.iocoder.yudao.framework.mq.core.util.RedisMessageUtils;
import cn.iocoder.yudao.adminserver.modules.system.mq.message.dict.SysDictDataRefreshMessage;
import org.springframework.data.redis.core.StringRedisTemplate;
import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@ -14,14 +13,14 @@ import javax.annotation.Resource;
public class SysDictDataProducer {
@Resource
private StringRedisTemplate stringRedisTemplate;
private RedisMQTemplate redisMQTemplate;
/**
* 发送 {@link SysDictDataRefreshMessage} 消息
*/
public void sendDictDataRefreshMessage() {
SysDictDataRefreshMessage message = new SysDictDataRefreshMessage();
RedisMessageUtils.sendChannelMessage(stringRedisTemplate, message);
redisMQTemplate.send(message);
}
}

View File

@ -1,8 +1,7 @@
package cn.iocoder.yudao.adminserver.modules.system.mq.producer.permission;
import cn.iocoder.yudao.framework.mq.core.util.RedisMessageUtils;
import cn.iocoder.yudao.adminserver.modules.system.mq.message.permission.SysMenuRefreshMessage;
import org.springframework.data.redis.core.StringRedisTemplate;
import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@ -14,14 +13,14 @@ import javax.annotation.Resource;
public class SysMenuProducer {
@Resource
private StringRedisTemplate stringRedisTemplate;
private RedisMQTemplate redisMQTemplate;
/**
* 发送 {@link SysMenuRefreshMessage} 消息
*/
public void sendMenuRefreshMessage() {
SysMenuRefreshMessage message = new SysMenuRefreshMessage();
RedisMessageUtils.sendChannelMessage(stringRedisTemplate, message);
redisMQTemplate.send(message);
}
}

View File

@ -1,8 +1,7 @@
package cn.iocoder.yudao.adminserver.modules.system.mq.producer.permission;
import cn.iocoder.yudao.framework.mq.core.util.RedisMessageUtils;
import cn.iocoder.yudao.adminserver.modules.system.mq.message.permission.SysRoleMenuRefreshMessage;
import org.springframework.data.redis.core.StringRedisTemplate;
import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@ -14,14 +13,14 @@ import javax.annotation.Resource;
public class SysPermissionProducer {
@Resource
private StringRedisTemplate stringRedisTemplate;
private RedisMQTemplate redisMQTemplate;
/**
* 发送 {@link SysRoleMenuRefreshMessage} 消息
*/
public void sendRoleMenuRefreshMessage() {
SysRoleMenuRefreshMessage message = new SysRoleMenuRefreshMessage();
RedisMessageUtils.sendChannelMessage(stringRedisTemplate, message);
redisMQTemplate.send(message);
}
}

View File

@ -1,8 +1,7 @@
package cn.iocoder.yudao.adminserver.modules.system.mq.producer.permission;
import cn.iocoder.yudao.framework.mq.core.util.RedisMessageUtils;
import cn.iocoder.yudao.adminserver.modules.system.mq.message.permission.SysRoleRefreshMessage;
import org.springframework.data.redis.core.StringRedisTemplate;
import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@ -16,14 +15,14 @@ import javax.annotation.Resource;
public class SysRoleProducer {
@Resource
private StringRedisTemplate stringRedisTemplate;
private RedisMQTemplate redisMQTemplate;
/**
* 发送 {@link SysRoleRefreshMessage} 消息
*/
public void sendRoleRefreshMessage() {
SysRoleRefreshMessage message = new SysRoleRefreshMessage();
RedisMessageUtils.sendChannelMessage(stringRedisTemplate, message);
redisMQTemplate.send(message);
}
}

View File

@ -1,15 +1,12 @@
package cn.iocoder.yudao.adminserver.modules.system.mq.producer.sms;
import cn.iocoder.yudao.framework.common.core.KeyValue;
import cn.iocoder.yudao.framework.mq.core.util.RedisMessageUtils;
import cn.iocoder.yudao.adminserver.modules.system.mq.message.sms.SysSmsChannelRefreshMessage;
import cn.iocoder.yudao.adminserver.modules.system.mq.message.sms.SysSmsTemplateRefreshMessage;
import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
/**
* Sms 短信相关消息的 Producer
@ -22,14 +19,14 @@ import java.util.List;
public class SysSmsProducer {
@Resource
private StringRedisTemplate stringRedisTemplate;
private RedisMQTemplate redisMQTemplate;
/**
* 发送 {@link SysSmsChannelRefreshMessage} 消息
*/
public void sendSmsChannelRefreshMessage() {
SysSmsChannelRefreshMessage message = new SysSmsChannelRefreshMessage();
RedisMessageUtils.sendChannelMessage(stringRedisTemplate, message);
redisMQTemplate.send(message);
}
/**
@ -37,7 +34,7 @@ public class SysSmsProducer {
*/
public void sendSmsTemplateRefreshMessage() {
SysSmsTemplateRefreshMessage message = new SysSmsTemplateRefreshMessage();
RedisMessageUtils.sendChannelMessage(stringRedisTemplate, message);
redisMQTemplate.send(message);
}
}

View File

@ -6,10 +6,12 @@ import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAu
import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthSocialLogin2ReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthSocialLoginReqVO;
import cn.iocoder.yudao.adminserver.modules.system.convert.auth.SysAuthConvert;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept.SysPostDO;
import cn.iocoder.yudao.adminserver.modules.system.enums.logger.SysLoginLogTypeEnum;
import cn.iocoder.yudao.adminserver.modules.system.enums.logger.SysLoginResultEnum;
import cn.iocoder.yudao.adminserver.modules.system.service.auth.SysAuthService;
import cn.iocoder.yudao.adminserver.modules.system.service.common.SysCaptchaService;
import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysPostService;
import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService;
import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.social.SysSocialUserDO;
@ -39,12 +41,14 @@ import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import static cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants.*;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static java.util.Collections.singleton;
/**
@ -75,6 +79,8 @@ public class SysAuthServiceImpl implements SysAuthService {
@Resource
private SysUserSessionCoreService userSessionCoreService;
@Resource
private SysPostService postService;
@Resource
private SysSocialCoreService socialService;
@ -86,7 +92,7 @@ public class SysAuthServiceImpl implements SysAuthService {
throw new UsernameNotFoundException(username);
}
// 创建 LoginUser 对象
return SysAuthConvert.INSTANCE.convert(user);
return this.buildLoginUser(user);
}
@Override
@ -99,9 +105,7 @@ public class SysAuthServiceImpl implements SysAuthService {
this.createLoginLog(user.getUsername(), SysLoginLogTypeEnum.LOGIN_MOCK, SysLoginResultEnum.SUCCESS);
// 创建 LoginUser 对象
LoginUser loginUser = SysAuthConvert.INSTANCE.convert(user);
loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId())); // 获取用户角色列表
return loginUser;
return this.buildLoginUser(user);
}
@Override
@ -109,18 +113,28 @@ public class SysAuthServiceImpl implements SysAuthService {
// 判断验证码是否正确
this.verifyCaptcha(reqVO.getUsername(), reqVO.getUuid(), reqVO.getCode());
// 使用账号密码进行登录
// 使用账号密码进行登录
LoginUser loginUser = this.login0(reqVO.getUsername(), reqVO.getPassword());
loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId())); // 获取用户角色列表
// 缓存登用户到 Redis 返回 sessionId 编号
// 缓存登用户到 Redis 返回 sessionId 编号
return userSessionCoreService.createUserSession(loginUser, userIp, userAgent);
}
private List<String> getUserPosts(Set<Long> postIds) {
if (CollUtil.isEmpty(postIds)) {
return Collections.emptyList();
}
return convertList(postService.getPosts(postIds), SysPostDO::getCode);
}
private void verifyCaptcha(String username, String captchaUUID, String captchaCode) {
// 如果验证码关闭则不进行校验
if (!captchaService.isCaptchaEnable()) {
return;
}
// 验证码不存在
final SysLoginLogTypeEnum logTypeEnum = SysLoginLogTypeEnum.LOGIN_USERNAME;
String code = captchaService.getCaptchaCode(captchaUUID);
// 验证码不存在
if (code == null) {
// 创建登录失败日志验证码不存在
this.createLoginLog(username, logTypeEnum, SysLoginResultEnum.CAPTCHA_NOT_FOUND);
@ -144,6 +158,7 @@ public class SysAuthServiceImpl implements SysAuthService {
// 调用 Spring Security AuthenticationManager#authenticate(...) 方法使用账号密码进行认证
// 在其内部会调用到 loadUserByUsername 方法获取 User 信息
authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
// org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(username);
} catch (BadCredentialsException badCredentialsException) {
this.createLoginLog(username, logTypeEnum, SysLoginResultEnum.BAD_CREDENTIALS);
throw exception(AUTH_LOGIN_BAD_CREDENTIALS);
@ -214,11 +229,10 @@ public class SysAuthServiceImpl implements SysAuthService {
this.createLoginLog(user.getUsername(), SysLoginLogTypeEnum.LOGIN_SOCIAL, SysLoginResultEnum.SUCCESS);
// 创建 LoginUser 对象
LoginUser loginUser = SysAuthConvert.INSTANCE.convert(user);
loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId())); // 获取用户角色列表
LoginUser loginUser = this.buildLoginUser(user);
// 绑定社交用户更新
socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, USER_TYPE_ENUM);
socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, userTypeEnum);
// 缓存登录用户到 Redis 返回 sessionId 编号
return userSessionCoreService.createUserSession(loginUser, userIp, userAgent);
@ -232,7 +246,6 @@ public class SysAuthServiceImpl implements SysAuthService {
// 使用账号密码进行登录
LoginUser loginUser = this.login0(reqVO.getUsername(), reqVO.getPassword());
loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId())); // 获取用户角色列表
// 绑定社交用户新增
socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, USER_TYPE_ENUM);
@ -285,15 +298,14 @@ public class SysAuthServiceImpl implements SysAuthService {
return null;
}
// 刷新 LoginUser 缓存
this.refreshLoginUserCache(token, loginUser);
return loginUser;
return this.refreshLoginUserCache(token, loginUser);
}
private void refreshLoginUserCache(String token, LoginUser loginUser) {
private LoginUser refreshLoginUserCache(String token, LoginUser loginUser) {
// 1/3 Session 超时时间刷新 LoginUser 缓存
if (System.currentTimeMillis() - loginUser.getUpdateTime().getTime() <
userSessionCoreService.getSessionTimeoutMillis() / 3) {
return;
return loginUser;
}
// 重新加载 SysUserDO 信息
@ -303,9 +315,18 @@ public class SysAuthServiceImpl implements SysAuthService {
}
// 刷新 LoginUser 缓存
LoginUser newLoginUser= this.buildLoginUser(user);
userSessionCoreService.refreshUserSession(token, newLoginUser);
return newLoginUser;
}
private LoginUser buildLoginUser(SysUserDO user) {
LoginUser loginUser = SysAuthConvert.INSTANCE.convert(user);
// 补全字段
loginUser.setDeptId(user.getDeptId());
loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId()));
userSessionCoreService.refreshUserSession(token, loginUser);
loginUser.setGroups(this.getUserPosts(user.getPostIds()));
return loginUser;
}
}

View File

@ -14,6 +14,13 @@ public interface SysCaptchaService {
*/
SysCaptchaImageRespVO getCaptchaImage();
/**
* 是否开启图片验证码
*
* @return 是否
*/
Boolean isCaptchaEnable();
/**
* 获得 uuid 对应的验证码
*

View File

@ -35,6 +35,11 @@ public class SysCaptchaServiceImpl implements SysCaptchaService {
return SysCaptchaConvert.INSTANCE.convert(uuid, captcha);
}
@Override
public Boolean isCaptchaEnable() {
return captchaProperties.getEnable();
}
@Override
public String getCaptchaCode(String uuid) {
return captchaRedisDAO.get(uuid);

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