diff --git a/.run/ruoyi-easyretry-server.run.xml b/.run/ruoyi-easyretry-server.run.xml new file mode 100644 index 000000000..2d5d3f58f --- /dev/null +++ b/.run/ruoyi-easyretry-server.run.xml @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/.run/ruoyi-monitor-admin.run.xml b/.run/ruoyi-monitor-admin.run.xml index 4837d6a42..095b3d7cb 100644 --- a/.run/ruoyi-monitor-admin.run.xml +++ b/.run/ruoyi-monitor-admin.run.xml @@ -2,7 +2,7 @@ - diff --git a/.run/ruoyi-powerjob-server.run.xml b/.run/ruoyi-powerjob-server.run.xml index 77a4af095..e36e2acf3 100644 --- a/.run/ruoyi-powerjob-server.run.xml +++ b/.run/ruoyi-powerjob-server.run.xml @@ -2,7 +2,7 @@ - diff --git a/.run/ruoyi-server.run.xml b/.run/ruoyi-server.run.xml index a29ff2a7f..0463c3439 100644 --- a/.run/ruoyi-server.run.xml +++ b/.run/ruoyi-server.run.xml @@ -2,7 +2,7 @@ - diff --git a/README.md b/README.md index a542b4752..e617bc81c 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus/blob/master/LICENSE) [![使用IntelliJ IDEA开发维护](https://img.shields.io/badge/IntelliJ%20IDEA-提供支持-blue.svg)](https://www.jetbrains.com/?from=RuoYi-Vue-Plus)
-[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-5.1.2-success.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus) +[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-5.2.0-success.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus) [![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.1-blue.svg)]() [![JDK-17](https://img.shields.io/badge/JDK-17-green.svg)]() [![JDK-21](https://img.shields.io/badge/JDK-21-green.svg)]() diff --git a/pom.xml b/pom.xml index f82e582f9..d16604238 100644 --- a/pom.xml +++ b/pom.xml @@ -13,29 +13,30 @@ RuoYi-Vue-Plus多租户管理系统 - 5.1.2 - 3.1.7 + 5.2.0-SNAPSHOT + 3.2.4 UTF-8 UTF-8 17 3.0.3 - 2.2.0 + 2.4.0 0.15.0 5.2.3 3.3.3 2.3 1.37.0 - 3.5.4 + 3.5.5 3.9.1 - 5.8.22 + 5.8.26 4.10.0 - 3.1.8 - 3.24.3 - 2.2.5 - 4.2.0 + 3.2.3 + 3.27.2 + 2.2.7 + 4.3.0 2.14.4 4.3.6 - 1.3.5 + 3.2.0 + 1.3.6 0.2.0 1.18.30 1.76 @@ -44,9 +45,10 @@ 2.7.0 - 1.12.600 + 2.25.15 + 0.29.13 - 2.2.0 + 3.2.0 1.2.83 3.0.4.2 @@ -57,6 +59,9 @@ 3.11.0 3.1.2 1.3.0 + + + 7.0.0 @@ -111,6 +116,14 @@ import + + org.flowable + flowable-bom + ${flowable.version} + pom + import + + me.zhyd.oauth @@ -213,7 +226,7 @@ com.baomidou - mybatis-plus-boot-starter + mybatis-plus-spring-boot3-starter ${mybatis-plus.version} @@ -235,10 +248,23 @@ ${okhttp.version} + - com.amazonaws - aws-java-sdk-s3 - ${aws-java-sdk-s3.version} + software.amazon.awssdk + s3 + ${aws.sdk.version} + + + + software.amazon.awssdk.crt + aws-crt + ${aws.crt.version} + + + + software.amazon.awssdk + s3-transfer-manager + ${aws.sdk.version} @@ -283,6 +309,23 @@ ${powerjob.version} + + + com.aizuda + easy-retry-client-starter + ${easyretry.version} + + + com.aizuda + easy-retry-client-core + ${easyretry.version} + + + com.aizuda + easy-retry-client-job-core + ${easyretry.version} + + com.alibaba transmittable-thread-local diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml index 46c320fcf..fa4750fc2 100644 --- a/ruoyi-admin/pom.xml +++ b/ruoyi-admin/pom.xml @@ -118,6 +118,12 @@ ruoyi-demo + + + org.dromara + ruoyi-workflow + + de.codecentric spring-boot-admin-starter-client @@ -134,6 +140,19 @@ JustAuth + + com.aizuda + easy-retry-client-starter + + + com.aizuda + easy-retry-client-core + + + com.aizuda + easy-retry-client-job-core + + diff --git a/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java b/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java index d0d79316e..43e689be3 100644 --- a/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java +++ b/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java @@ -23,9 +23,10 @@ import org.dromara.common.social.config.properties.SocialLoginConfigProperties; import org.dromara.common.social.config.properties.SocialProperties; import org.dromara.common.social.utils.SocialUtils; import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.common.websocket.dto.WebSocketMessageDto; import org.dromara.common.websocket.utils.WebSocketUtils; -import org.dromara.system.domain.SysClient; import org.dromara.system.domain.bo.SysTenantBo; +import org.dromara.system.domain.vo.SysClientVo; import org.dromara.system.domain.vo.SysTenantVo; import org.dromara.system.service.ISysClientService; import org.dromara.system.service.ISysConfigService; @@ -81,7 +82,7 @@ public class AuthController { // 授权类型和客户端id String clientId = loginBody.getClientId(); String grantType = loginBody.getGrantType(); - SysClient client = clientService.queryByClientId(clientId); + SysClientVo client = clientService.queryByClientId(clientId); // 查询不到 client 或 client 内不包含 grantType if (ObjectUtil.isNull(client) || !StringUtils.contains(client.getGrantType(), grantType)) { log.info("客户端id: {} 认证类型:{} 异常!.", clientId, grantType); @@ -96,7 +97,10 @@ public class AuthController { Long userId = LoginHelper.getUserId(); scheduledExecutorService.schedule(() -> { - WebSocketUtils.sendMessage(userId, "欢迎登录RuoYi-Vue-Plus后台管理系统"); + WebSocketMessageDto dto = new WebSocketMessageDto(); + dto.setMessage("欢迎登录RuoYi-Vue-Plus后台管理系统"); + dto.setSessionKeys(List.of(userId)); + WebSocketUtils.publishMessage(dto); }, 3, TimeUnit.SECONDS); return R.ok(loginVo); } diff --git a/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java b/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java index ef33f5b6f..1a476a94a 100644 --- a/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java +++ b/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java @@ -5,6 +5,9 @@ import cn.hutool.captcha.AbstractCaptcha; import cn.hutool.captcha.generator.CodeGenerator; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.RandomUtil; +import jakarta.validation.constraints.NotBlank; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.dromara.common.core.constant.Constants; import org.dromara.common.core.constant.GlobalConstants; import org.dromara.common.core.domain.R; @@ -21,11 +24,7 @@ import org.dromara.common.web.enums.CaptchaType; import org.dromara.sms4j.api.SmsBlend; import org.dromara.sms4j.api.entity.SmsResponse; import org.dromara.sms4j.core.factory.SmsFactory; -import org.dromara.sms4j.provider.enumerate.SupplierType; import org.dromara.web.domain.vo.CaptchaVo; -import jakarta.validation.constraints.NotBlank; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; @@ -66,11 +65,11 @@ public class CaptchaController { String templateId = ""; LinkedHashMap map = new LinkedHashMap<>(1); map.put("code", code); - SmsBlend smsBlend = SmsFactory.createSmsBlend(SupplierType.ALIBABA); + SmsBlend smsBlend = SmsFactory.getSmsBlend("config1"); SmsResponse smsResponse = smsBlend.sendMessage(phonenumber, templateId, map); - if (!"OK".equals(smsResponse.getCode())) { + if (!smsResponse.isSuccess()) { log.error("验证码短信发送异常 => {}", smsResponse); - return R.fail(smsResponse.getMessage()); + return R.fail(smsResponse.getData().toString()); } return R.ok(); } @@ -121,6 +120,7 @@ public class CaptchaController { AbstractCaptcha captcha = SpringUtils.getBean(captchaProperties.getCategory().getClazz()); captcha.setGenerator(codeGenerator); captcha.createCode(); + // 如果是数学验证码,使用SpEL表达式处理验证码结果 String code = captcha.getCode(); if (isMath) { ExpressionParser parser = new SpelExpressionParser(); diff --git a/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/TenantListVo.java b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/TenantListVo.java index 4d4bc89eb..db9c2712c 100644 --- a/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/TenantListVo.java +++ b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/TenantListVo.java @@ -13,10 +13,19 @@ import lombok.Data; @AutoMapper(target = SysTenantVo.class) public class TenantListVo { + /** + * 租户编号 + */ private String tenantId; + /** + * 企业名称 + */ private String companyName; + /** + * 域名 + */ private String domain; } diff --git a/ruoyi-admin/src/main/java/org/dromara/web/listener/UserActionListener.java b/ruoyi-admin/src/main/java/org/dromara/web/listener/UserActionListener.java index 6d67fb112..a4724043b 100644 --- a/ruoyi-admin/src/main/java/org/dromara/web/listener/UserActionListener.java +++ b/ruoyi-admin/src/main/java/org/dromara/web/listener/UserActionListener.java @@ -10,7 +10,6 @@ import lombok.extern.slf4j.Slf4j; import org.dromara.common.core.constant.CacheConstants; import org.dromara.common.core.constant.Constants; import org.dromara.common.core.domain.dto.UserOnlineDTO; -import org.dromara.common.core.domain.model.LoginUser; import org.dromara.common.core.utils.MessageUtils; import org.dromara.common.core.utils.ServletUtils; import org.dromara.common.core.utils.SpringUtils; @@ -18,6 +17,7 @@ import org.dromara.common.core.utils.ip.AddressUtils; import org.dromara.common.log.event.LogininforEvent; import org.dromara.common.redis.utils.RedisUtils; import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.tenant.helper.TenantHelper; import org.dromara.web.service.SysLoginService; import org.springframework.stereotype.Component; @@ -43,7 +43,6 @@ public class UserActionListener implements SaTokenListener { public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginModel loginModel) { UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent")); String ip = ServletUtils.getClientIP(); - LoginUser user = LoginHelper.getLoginUser(); UserOnlineDTO dto = new UserOnlineDTO(); dto.setIpaddr(ip); dto.setLoginLocation(AddressUtils.getRealAddressByIP(ip)); @@ -51,25 +50,29 @@ public class UserActionListener implements SaTokenListener { dto.setOs(userAgent.getOs().getName()); dto.setLoginTime(System.currentTimeMillis()); dto.setTokenId(tokenValue); - dto.setUserName(user.getUsername()); - dto.setClientKey(user.getClientKey()); - dto.setDeviceType(user.getDeviceType()); - dto.setDeptName(user.getDeptName()); - if(tokenConfig.getTimeout() == -1) { - RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto); - } else { - RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto, Duration.ofSeconds(tokenConfig.getTimeout())); - } + String username = (String) loginModel.getExtra(LoginHelper.USER_NAME_KEY); + String tenantId = (String) loginModel.getExtra(LoginHelper.TENANT_KEY); + dto.setUserName(username); + dto.setClientKey((String) loginModel.getExtra(LoginHelper.CLIENT_KEY)); + dto.setDeviceType(loginModel.getDevice()); + dto.setDeptName((String) loginModel.getExtra(LoginHelper.DEPT_NAME_KEY)); + TenantHelper.dynamic(tenantId, () -> { + if(tokenConfig.getTimeout() == -1) { + RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto); + } else { + RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto, Duration.ofSeconds(tokenConfig.getTimeout())); + } + }); // 记录登录日志 LogininforEvent logininforEvent = new LogininforEvent(); - logininforEvent.setTenantId(user.getTenantId()); - logininforEvent.setUsername(user.getUsername()); + logininforEvent.setTenantId(tenantId); + logininforEvent.setUsername(username); logininforEvent.setStatus(Constants.LOGIN_SUCCESS); logininforEvent.setMessage(MessageUtils.message("user.login.success")); logininforEvent.setRequest(ServletUtils.getRequest()); SpringUtils.context().publishEvent(logininforEvent); // 更新登录信息 - loginService.recordLoginInfo(user.getUserId(), ip); + loginService.recordLoginInfo((Long) loginModel.getExtra(LoginHelper.USER_KEY), ip); log.info("user doLogin, userId:{}, token:{}", loginId, tokenValue); } diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/IAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/IAuthStrategy.java index d4f9c73f7..a75b9131e 100644 --- a/ruoyi-admin/src/main/java/org/dromara/web/service/IAuthStrategy.java +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/IAuthStrategy.java @@ -4,6 +4,7 @@ package org.dromara.web.service; import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.utils.SpringUtils; import org.dromara.system.domain.SysClient; +import org.dromara.system.domain.vo.SysClientVo; import org.dromara.web.domain.vo.LoginVo; /** @@ -17,8 +18,13 @@ public interface IAuthStrategy { /** * 登录 + * + * @param body 登录对象 + * @param client 授权管理视图对象 + * @param grantType 授权类型 + * @return 登录验证信息 */ - static LoginVo login(String body, SysClient client, String grantType) { + static LoginVo login(String body, SysClientVo client, String grantType) { // 授权类型和客户端id String beanName = grantType + BASE_NAME; if (!SpringUtils.containsBean(beanName)) { @@ -30,7 +36,11 @@ public interface IAuthStrategy { /** * 登录 + * + * @param body 登录对象 + * @param client 授权管理视图对象 + * @return 登录验证信息 */ - LoginVo login(String body, SysClient client); + LoginVo login(String body, SysClientVo client); } diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java b/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java index 37802b7f0..b2c9d3a6b 100644 --- a/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java @@ -25,13 +25,9 @@ import org.dromara.common.tenant.exception.TenantException; import org.dromara.common.tenant.helper.TenantHelper; import org.dromara.system.domain.SysUser; import org.dromara.system.domain.bo.SysSocialBo; -import org.dromara.system.domain.vo.SysSocialVo; -import org.dromara.system.domain.vo.SysTenantVo; -import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.domain.vo.*; import org.dromara.system.mapper.SysUserMapper; -import org.dromara.system.service.ISysPermissionService; -import org.dromara.system.service.ISysSocialService; -import org.dromara.system.service.ISysTenantService; +import org.dromara.system.service.*; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @@ -59,6 +55,8 @@ public class SysLoginService { private final ISysTenantService tenantService; private final ISysPermissionService permissionService; private final ISysSocialService sysSocialService; + private final ISysRoleService roleService; + private final ISysDeptService deptService; private final SysUserMapper userMapper; @@ -146,9 +144,15 @@ public class SysLoginService { loginUser.setUserType(user.getUserType()); loginUser.setMenuPermission(permissionService.getMenuPermission(user.getUserId())); loginUser.setRolePermission(permissionService.getRolePermission(user.getUserId())); - loginUser.setDeptName(ObjectUtil.isNull(user.getDept()) ? "" : user.getDept().getDeptName()); - List roles = BeanUtil.copyToList(user.getRoles(), RoleDTO.class); - loginUser.setRoles(roles); + TenantHelper.dynamic(user.getTenantId(), () -> { + SysDeptVo dept = null; + if (ObjectUtil.isNotNull(user.getDeptId())) { + dept = deptService.selectDeptById(user.getDeptId()); + } + loginUser.setDeptName(ObjectUtil.isNull(dept) ? "" : dept.getDeptName()); + List roles = roleService.selectRolesByUserId(user.getUserId()); + loginUser.setRoles(BeanUtil.copyToList(roles, RoleDTO.class)); + }); return loginUser; } diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java b/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java index f38d074e3..14fa0cc27 100644 --- a/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java @@ -82,7 +82,7 @@ public class SysRegisterService { * @param uuid 唯一标识 */ public void validateCaptcha(String tenantId, String username, String code, String uuid) { - String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.defaultString(uuid, ""); + String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.blankToDefault(uuid, ""); String captcha = RedisUtils.getCacheObject(verifyKey); RedisUtils.deleteObject(verifyKey); if (captcha == null) { diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java index a2636bc22..38fdc448b 100644 --- a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java @@ -23,6 +23,7 @@ import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.common.tenant.helper.TenantHelper; import org.dromara.system.domain.SysClient; import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.vo.SysClientVo; import org.dromara.system.domain.vo.SysUserVo; import org.dromara.system.mapper.SysUserMapper; import org.dromara.web.domain.vo.LoginVo; @@ -44,7 +45,7 @@ public class EmailAuthStrategy implements IAuthStrategy { private final SysUserMapper userMapper; @Override - public LoginVo login(String body, SysClient client) { + public LoginVo login(String body, SysClientVo client) { EmailLoginBody loginBody = JsonUtils.parseObject(body, EmailLoginBody.class); ValidatorUtils.validate(loginBody); String tenantId = loginBody.getTenantId(); @@ -90,9 +91,7 @@ public class EmailAuthStrategy implements IAuthStrategy { private SysUserVo loadUserByEmail(String tenantId, String email) { return TenantHelper.dynamic(tenantId, () -> { - SysUser user = userMapper.selectOne(new LambdaQueryWrapper() - .select(SysUser::getEmail, SysUser::getStatus) - .eq(SysUser::getEmail, email)); + SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper().eq(SysUser::getEmail, email)); if (ObjectUtil.isNull(user)) { log.info("登录用户:{} 不存在.", email); throw new UserException("user.not.exists", email); @@ -100,7 +99,7 @@ public class EmailAuthStrategy implements IAuthStrategy { log.info("登录用户:{} 已被停用.", email); throw new UserException("user.blocked", email); } - return userMapper.selectUserByEmail(email); + return user; }); } diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java index bcb5916d3..cd33ea408 100644 --- a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java @@ -26,6 +26,7 @@ import org.dromara.common.tenant.helper.TenantHelper; import org.dromara.common.web.config.properties.CaptchaProperties; import org.dromara.system.domain.SysClient; import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.vo.SysClientVo; import org.dromara.system.domain.vo.SysUserVo; import org.dromara.system.mapper.SysUserMapper; import org.dromara.web.domain.vo.LoginVo; @@ -48,7 +49,7 @@ public class PasswordAuthStrategy implements IAuthStrategy { private final SysUserMapper userMapper; @Override - public LoginVo login(String body, SysClient client) { + public LoginVo login(String body, SysClientVo client) { PasswordLoginBody loginBody = JsonUtils.parseObject(body, PasswordLoginBody.class); ValidatorUtils.validate(loginBody); String tenantId = loginBody.getTenantId(); @@ -109,9 +110,7 @@ public class PasswordAuthStrategy implements IAuthStrategy { private SysUserVo loadUserByUsername(String tenantId, String username) { return TenantHelper.dynamic(tenantId, () -> { - SysUser user = userMapper.selectOne(new LambdaQueryWrapper() - .select(SysUser::getUserName, SysUser::getStatus) - .eq(SysUser::getUserName, username)); + SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper().eq(SysUser::getUserName, username)); if (ObjectUtil.isNull(user)) { log.info("登录用户:{} 不存在.", username); throw new UserException("user.not.exists", username); @@ -119,7 +118,7 @@ public class PasswordAuthStrategy implements IAuthStrategy { log.info("登录用户:{} 已被停用.", username); throw new UserException("user.blocked", username); } - return userMapper.selectUserByUserName(username); + return user; }); } diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java index a4fa11c8e..f883632f9 100644 --- a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java @@ -23,6 +23,7 @@ import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.common.tenant.helper.TenantHelper; import org.dromara.system.domain.SysClient; import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.vo.SysClientVo; import org.dromara.system.domain.vo.SysUserVo; import org.dromara.system.mapper.SysUserMapper; import org.dromara.web.domain.vo.LoginVo; @@ -44,7 +45,7 @@ public class SmsAuthStrategy implements IAuthStrategy { private final SysUserMapper userMapper; @Override - public LoginVo login(String body, SysClient client) { + public LoginVo login(String body, SysClientVo client) { SmsLoginBody loginBody = JsonUtils.parseObject(body, SmsLoginBody.class); ValidatorUtils.validate(loginBody); String tenantId = loginBody.getTenantId(); @@ -90,9 +91,7 @@ public class SmsAuthStrategy implements IAuthStrategy { private SysUserVo loadUserByPhonenumber(String tenantId, String phonenumber) { return TenantHelper.dynamic(tenantId, () -> { - SysUser user = userMapper.selectOne(new LambdaQueryWrapper() - .select(SysUser::getPhonenumber, SysUser::getStatus) - .eq(SysUser::getPhonenumber, phonenumber)); + SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper().eq(SysUser::getPhonenumber, phonenumber)); if (ObjectUtil.isNull(user)) { log.info("登录用户:{} 不存在.", phonenumber); throw new UserException("user.not.exists", phonenumber); @@ -100,7 +99,7 @@ public class SmsAuthStrategy implements IAuthStrategy { log.info("登录用户:{} 已被停用.", phonenumber); throw new UserException("user.blocked", phonenumber); } - return userMapper.selectUserByPhonenumber(phonenumber); + return user; }); } diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java index a12386e94..66941651c 100644 --- a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java @@ -7,7 +7,6 @@ import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.http.HttpUtil; import cn.hutool.http.Method; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import me.zhyd.oauth.model.AuthResponse; @@ -23,8 +22,7 @@ import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.common.social.config.properties.SocialProperties; import org.dromara.common.social.utils.SocialUtils; import org.dromara.common.tenant.helper.TenantHelper; -import org.dromara.system.domain.SysClient; -import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.vo.SysClientVo; import org.dromara.system.domain.vo.SysSocialVo; import org.dromara.system.domain.vo.SysUserVo; import org.dromara.system.mapper.SysUserMapper; @@ -59,7 +57,7 @@ public class SocialAuthStrategy implements IAuthStrategy { * @param client 客户端信息 */ @Override - public LoginVo login(String body, SysClient client) { + public LoginVo login(String body, SysClientVo client) { SocialLoginBody loginBody = JsonUtils.parseObject(body, SocialLoginBody.class); ValidatorUtils.validate(loginBody); AuthResponse response = SocialUtils.loginAuth( @@ -83,11 +81,16 @@ public class SocialAuthStrategy implements IAuthStrategy { if (CollUtil.isEmpty(list)) { throw new ServiceException("你还没有绑定第三方账号,绑定后才可以登录!"); } - Optional opt = list.stream().filter(x -> x.getTenantId().equals(loginBody.getTenantId())).findAny(); - if (opt.isEmpty()) { - throw new ServiceException("对不起,你没有权限登录当前租户!"); + SysSocialVo social; + if (TenantHelper.isEnable()) { + Optional opt = list.stream().filter(x -> x.getTenantId().equals(loginBody.getTenantId())).findAny(); + if (opt.isEmpty()) { + throw new ServiceException("对不起,你没有权限登录当前租户!"); + } + social = opt.get(); + } else { + social = list.get(0); } - SysSocialVo social = opt.get(); // 查找用户 SysUserVo user = loadUser(social.getTenantId(), social.getUserId()); @@ -114,9 +117,7 @@ public class SocialAuthStrategy implements IAuthStrategy { private SysUserVo loadUser(String tenantId, Long userId) { return TenantHelper.dynamic(tenantId, () -> { - SysUser user = userMapper.selectOne(new LambdaQueryWrapper() - .select(SysUser::getUserName, SysUser::getStatus) - .eq(SysUser::getUserId, userId)); + SysUserVo user = userMapper.selectVoById(userId); if (ObjectUtil.isNull(user)) { log.info("登录用户:{} 不存在.", ""); throw new UserException("user.not.exists", ""); @@ -124,7 +125,7 @@ public class SocialAuthStrategy implements IAuthStrategy { log.info("登录用户:{} 已被停用.", ""); throw new UserException("user.blocked", ""); } - return userMapper.selectUserByUserName(user.getUserName()); + return user; }); } diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java index e5aef1fad..ccab778cf 100644 --- a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java @@ -12,6 +12,7 @@ import org.dromara.common.core.utils.ValidatorUtils; import org.dromara.common.json.utils.JsonUtils; import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.system.domain.SysClient; +import org.dromara.system.domain.vo.SysClientVo; import org.dromara.system.domain.vo.SysUserVo; import org.dromara.web.domain.vo.LoginVo; import org.dromara.web.service.IAuthStrategy; @@ -31,7 +32,7 @@ public class XcxAuthStrategy implements IAuthStrategy { private final SysLoginService loginService; @Override - public LoginVo login(String body, SysClient client) { + public LoginVo login(String body, SysClientVo client) { XcxLoginBody loginBody = JsonUtils.parseObject(body, XcxLoginBody.class); ValidatorUtils.validate(loginBody); // xcxCode 为 小程序调用 wx.login 授权后获取 diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml index 7065d893c..d41cdba49 100644 --- a/ruoyi-admin/src/main/resources/application-dev.yml +++ b/ruoyi-admin/src/main/resources/application-dev.yml @@ -24,6 +24,20 @@ powerjob: server-address: 127.0.0.1:7700 store-strategy: disk +--- # easy-retry 配置 +easy-retry: + enabled: true + # 需要在EasyRetry后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务 + group-name: "ruoyi_group" + # EasyRetry接入验证令牌 详见 script/sql/easy_retry.sql `er_group_config` 表 + token: "ER_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT" + server: + host: 127.0.0.1 + port: 1788 + # 详见 script/sql/easy_retry.sql `er_namespace` 表 + namespace: ${spring.profiles.active} + + --- # 数据源配置 spring: datasource: @@ -149,36 +163,40 @@ mail: connectionTimeout: 0 --- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商 -# https://wind.kim/doc/start 文档地址 各个厂商可同时使用 +# https://sms4j.com/doc3/ 差异配置文档地址 支持单厂商多配置,可以配置多个同时使用 sms: - # 阿里云 dysmsapi.aliyuncs.com - alibaba: - #请求地址 默认为 dysmsapi.aliyuncs.com 如无特殊改变可以不用设置 - requestUrl: dysmsapi.aliyuncs.com - #阿里云的accessKey - accessKeyId: xxxxxxx - #阿里云的accessKeySecret - accessKeySecret: xxxxxxx - #短信签名 - signature: 测试 - tencent: - #请求地址默认为 sms.tencentcloudapi.com 如无特殊改变可不用设置 - requestUrl: sms.tencentcloudapi.com - #腾讯云的accessKey - accessKeyId: xxxxxxx - #腾讯云的accessKeySecret - accessKeySecret: xxxxxxx - #短信签名 - signature: 测试 - #短信sdkAppId - sdkAppId: appid - #地域信息默认为 ap-guangzhou 如无特殊改变可不用设置 - territory: ap-guangzhou + # 配置源类型用于标定配置来源(interface,yaml) + config-type: yaml + # 用于标定yml中的配置是否开启短信拦截,接口配置不受此限制 + restricted: true + # 短信拦截限制单手机号每分钟最大发送,只对开启了拦截的配置有效 + minute-max: 1 + # 短信拦截限制单手机号每日最大发送量,只对开启了拦截的配置有效 + account-max: 30 + # 以下配置来自于 org.dromara.sms4j.provider.config.BaseConfig类中 + blends: + # 唯一ID 用于发送短信寻找具体配置 随便定义别用中文即可 + # 可以同时存在两个相同厂商 例如: ali1 ali2 两个不同的阿里短信账号 也可用于区分租户 + config1: + # 框架定义的厂商名称标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分 + supplier: alibaba + # 有些称为accessKey有些称之为apiKey,也有称为sdkKey或者appId。 + access-key-id: 您的accessKey + # 称为accessSecret有些称之为apiSecret + access-key-secret: 您的accessKeySecret + signature: 您的短信签名 + sdk-app-id: 您的sdkAppId + config2: + # 厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分 + supplier: tencent + access-key-id: 您的accessKey + access-key-secret: 您的accessKeySecret + signature: 您的短信签名 + sdk-app-id: 您的sdkAppId --- # 三方授权 justauth: - enabled: true # 前端外网访问地址 address: http://localhost:80 type: @@ -189,6 +207,13 @@ justauth: client-id: 876892492581044224 client-secret: x1Y5MTMwNzIwMjMxNTM4NDc3Mzche8 redirect-uri: ${justauth.address}/social-callback?source=maxkey + topiam: + # topiam 服务器地址 + server-url: http://127.0.0.1:1989/api/v1/authorize/y0q************spq***********8ol + client-id: 449c4*********937************759 + client-secret: ac7***********1e0************28d + redirect-uri: ${justauth.address}/social-callback?source=topiam + scopes: [openid, email, phone, profile] qq: client-id: 10**********6 client-secret: 1f7d08**********5b7**********29e diff --git a/ruoyi-admin/src/main/resources/application-prod.yml b/ruoyi-admin/src/main/resources/application-prod.yml index 782a680a1..3545a4c4e 100644 --- a/ruoyi-admin/src/main/resources/application-prod.yml +++ b/ruoyi-admin/src/main/resources/application-prod.yml @@ -27,6 +27,19 @@ powerjob: server-address: 127.0.0.1:7700 store-strategy: disk +--- # easy-retry 配置 +easy-retry: + enabled: false + # 需要在EasyRetry后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务 + group-name: "ruoyi_group" + # EasyRetry接入验证令牌 详见 script/sql/easy_retry.sql `er_group_config` 表 + token: "ER_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT" + server: + host: 127.0.0.1 + port: 1788 + # 详见 script/sql/easy_retry.sql `er_namespace` 表 + namespace: ${spring.profiles.active} + --- # 数据源配置 spring: datasource: @@ -46,7 +59,7 @@ spring: driverClassName: com.mysql.cj.jdbc.Driver # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562 # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题) - url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true + url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true username: root password: root # 从库数据源 @@ -54,7 +67,7 @@ spring: lazy: true type: ${spring.datasource.type} driverClassName: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true + url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true username: password: # oracle: @@ -152,35 +165,39 @@ mail: connectionTimeout: 0 --- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商 -# https://wind.kim/doc/start 文档地址 各个厂商可同时使用 +# https://sms4j.com/doc3/ 差异配置文档地址 支持单厂商多配置,可以配置多个同时使用 sms: - # 阿里云 dysmsapi.aliyuncs.com - alibaba: - #请求地址 默认为 dysmsapi.aliyuncs.com 如无特殊改变可以不用设置 - requestUrl: dysmsapi.aliyuncs.com - #阿里云的accessKey - accessKeyId: xxxxxxx - #阿里云的accessKeySecret - accessKeySecret: xxxxxxx - #短信签名 - signature: 测试 - tencent: - #请求地址默认为 sms.tencentcloudapi.com 如无特殊改变可不用设置 - requestUrl: sms.tencentcloudapi.com - #腾讯云的accessKey - accessKeyId: xxxxxxx - #腾讯云的accessKeySecret - accessKeySecret: xxxxxxx - #短信签名 - signature: 测试 - #短信sdkAppId - sdkAppId: appid - #地域信息默认为 ap-guangzhou 如无特殊改变可不用设置 - territory: ap-guangzhou + # 配置源类型用于标定配置来源(interface,yaml) + config-type: yaml + # 用于标定yml中的配置是否开启短信拦截,接口配置不受此限制 + restricted: true + # 短信拦截限制单手机号每分钟最大发送,只对开启了拦截的配置有效 + minute-max: 1 + # 短信拦截限制单手机号每日最大发送量,只对开启了拦截的配置有效 + account-max: 30 + # 以下配置来自于 org.dromara.sms4j.provider.config.BaseConfig类中 + blends: + # 唯一ID 用于发送短信寻找具体配置 随便定义别用中文即可 + # 可以同时存在两个相同厂商 例如: ali1 ali2 两个不同的阿里短信账号 也可用于区分租户 + config1: + # 框架定义的厂商名称标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分 + supplier: alibaba + # 有些称为accessKey有些称之为apiKey,也有称为sdkKey或者appId。 + access-key-id: 您的accessKey + # 称为accessSecret有些称之为apiSecret + access-key-secret: 您的accessKeySecret + signature: 您的短信签名 + sdk-app-id: 您的sdkAppId + config2: + # 厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分 + supplier: tencent + access-key-id: 您的accessKey + access-key-secret: 您的accessKeySecret + signature: 您的短信签名 + sdk-app-id: 您的sdkAppId --- # 三方授权 justauth: - enabled: true # 前端外网访问地址 address: http://localhost:80 type: @@ -191,6 +208,13 @@ justauth: client-id: 876892492581044224 client-secret: x1Y5MTMwNzIwMjMxNTM4NDc3Mzche8 redirect-uri: ${justauth.address}/social-callback?source=maxkey + topiam: + # topiam 服务器地址 + server-url: http://127.0.0.1:1989/api/v1/authorize/y0q************spq***********8ol + client-id: 449c4*********937************759 + client-secret: ac7***********1e0************28d + redirect-uri: ${justauth.address}/social-callback?source=topiam + scopes: [ openid, email, phone, profile ] qq: client-id: 10**********6 client-secret: 1f7d08**********5b7**********29e diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index 599886c13..448a2ef32 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -5,7 +5,7 @@ ruoyi: # 版本 version: ${revision} # 版权年份 - copyrightYear: 2023 + copyrightYear: 2024 captcha: enable: true @@ -47,6 +47,7 @@ logging: org.dromara: @logging.level@ org.springframework: warn tech.powerjob.worker.background: warn + org.mybatis.spring.mapper: error config: classpath:logback-plus.xml # 用户配置 @@ -61,6 +62,10 @@ user: spring: application: name: ${ruoyi.name} + threads: + # 开启虚拟线程 仅jdk21可用 + virtual: + enabled: false # 资源信息 messages: # 国际化资源文件路径 @@ -118,6 +123,9 @@ security: # actuator 监控配置 - /actuator - /actuator/** + # EasyRetry Job 分派 @see com.aizuda.easy.retry.client.job.core.client.JobEndPoint + - /job/dispatch/v1 + - /job/stop/v1 # 多租户配置 tenant: @@ -138,8 +146,7 @@ tenant: # MyBatisPlus配置 # https://baomidou.com/config/ mybatis-plus: - # 不支持多包, 如有需要可在注解配置 或 提升扫包等级 - # 例如 com.**.**.mapper + # 多包名使用 例如 org.dromara.**.mapper,org.xxx.**.mapper mapperPackage: org.dromara.**.mapper # 对应的 XML 文件位置 mapperLocations: classpath*:mapper/**/*Mapper.xml @@ -226,6 +233,7 @@ xss: urlPatterns: /system/*,/monitor/*,/tool/* # 全局线程池相关配置 +# 如使用JDK21请直接使用虚拟线程 不要开启此配置 thread-pool: # 是否开启线程池 enabled: false @@ -261,3 +269,21 @@ websocket: path: /resource/websocket # 设置访问源地址 allowedOrigins: '*' + +--- #flowable配置 +flowable: + async-executor-activate: false #关闭定时任务JOB + # 将databaseSchemaUpdate设置为true。当Flowable发现库与数据库表结构不一致时,会自动将数据库表结构升级至新版本。 + database-schema-update: true + activity-font-name: 宋体 + label-font-name: 宋体 + annotation-font-name: 宋体 + # 关闭各个模块生成表,目前只使用工作流基础表 + idm: + enabled: false + cmmn: + enabled: false + dmn: + enabled: false + app: + enabled: false diff --git a/ruoyi-admin/src/main/resources/ip2region.xdb b/ruoyi-admin/src/main/resources/ip2region.xdb index 31f96a1fb..7052c0571 100644 Binary files a/ruoyi-admin/src/main/resources/ip2region.xdb and b/ruoyi-admin/src/main/resources/ip2region.xdb differ diff --git a/ruoyi-common/ruoyi-common-bom/pom.xml b/ruoyi-common/ruoyi-common-bom/pom.xml index 004b035de..4a2dc1ceb 100644 --- a/ruoyi-common/ruoyi-common-bom/pom.xml +++ b/ruoyi-common/ruoyi-common-bom/pom.xml @@ -14,7 +14,7 @@ - 5.1.2 + 5.2.0-SNAPSHOT diff --git a/ruoyi-common/ruoyi-common-core/pom.xml b/ruoyi-common/ruoyi-common-core/pom.xml index ad37e90db..5925c9b3c 100644 --- a/ruoyi-common/ruoyi-common-core/pom.xml +++ b/ruoyi-common/ruoyi-common-core/pom.xml @@ -94,6 +94,11 @@ ip2region + + com.alibaba + transmittable-thread-local + + diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ApplicationConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ApplicationConfig.java index 07500ba1b..d12008706 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ApplicationConfig.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ApplicationConfig.java @@ -2,6 +2,7 @@ package org.dromara.common.core.config; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.scheduling.annotation.EnableAsync; /** * 程序注解配置 @@ -11,6 +12,7 @@ import org.springframework.context.annotation.EnableAspectJAutoProxy; @AutoConfiguration // 表示通过aop框架暴露该代理对象,AopContext能够访问 @EnableAspectJAutoProxy(exposeProxy = true) +@EnableAsync(proxyTargetClass = true) public class ApplicationConfig { } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/AsyncConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/AsyncConfig.java index 9a32afe55..cd01e33d5 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/AsyncConfig.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/AsyncConfig.java @@ -5,18 +5,19 @@ import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.utils.SpringUtils; import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.core.task.VirtualThreadTaskExecutor; import org.springframework.scheduling.annotation.AsyncConfigurer; -import org.springframework.scheduling.annotation.EnableAsync; import java.util.Arrays; import java.util.concurrent.Executor; /** * 异步配置 + *

+ * 如果未使用虚拟线程则生效 * * @author Lion Li */ -@EnableAsync(proxyTargetClass = true) @AutoConfiguration public class AsyncConfig implements AsyncConfigurer { @@ -25,6 +26,9 @@ public class AsyncConfig implements AsyncConfigurer { */ @Override public Executor getAsyncExecutor() { + if(SpringUtils.isVirtual()) { + return new VirtualThreadTaskExecutor("async-"); + } return SpringUtils.getBean("scheduledExecutorService"); } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java index e59277aae..28ba17739 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java @@ -35,6 +35,11 @@ public interface CacheNames { */ String SYS_TENANT = GlobalConstants.GLOBAL_REDIS_KEY + "sys_tenant#30d"; + /** + * 客户端 + */ + String SYS_CLIENT = GlobalConstants.GLOBAL_REDIS_KEY + "sys_client#30d"; + /** * 用户账户 */ diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/RegexConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/RegexConstants.java new file mode 100644 index 000000000..77eed8c09 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/RegexConstants.java @@ -0,0 +1,54 @@ +package org.dromara.common.core.constant; + +import cn.hutool.core.lang.RegexPool; + +/** + * 常用正则表达式字符串 + *

+ * 常用正则表达式集合,更多正则见: https://any86.github.io/any-rule/ + * + * @author Feng + */ +public interface RegexConstants extends RegexPool { + + /** + * 字典类型必须以字母开头,且只能为(小写字母,数字,下滑线) + */ + String DICTIONARY_TYPE = "^[a-z][a-z0-9_]*$"; + + /** + * 权限标识必须符合 tool:build:list 格式,或者空字符串 + */ + String PERMISSION_STRING = "^(|^[a-zA-Z0-9_]+:[a-zA-Z0-9_]+:[a-zA-Z0-9_]+)$"; + + /** + * 身份证号码(后6位) + */ + String ID_CARD_LAST_6 = "^(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$"; + + /** + * QQ号码 + */ + String QQ_NUMBER = "^[1-9][0-9]\\d{4,9}$"; + + /** + * 邮政编码 + */ + String POSTAL_CODE = "^[1-9]\\d{5}$"; + + /** + * 注册账号 + */ + String ACCOUNT = "^[a-zA-Z][a-zA-Z0-9_]{4,15}$"; + + /** + * 密码:包含至少8个字符,包括大写字母、小写字母、数字和特殊字符 + */ + String PASSWORD = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,}$"; + + /** + * 通用状态(0表示正常,1表示停用) + */ + String STATUS = "^[01]$"; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/ServiceException.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/ServiceException.java index 4fb097a88..e9dc6ec9b 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/ServiceException.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/ServiceException.java @@ -1,9 +1,6 @@ package org.dromara.common.core.exception; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; +import lombok.*; import java.io.Serial; @@ -45,19 +42,11 @@ public final class ServiceException extends RuntimeException { this.code = code; } - public String getDetailMessage() { - return detailMessage; - } - @Override public String getMessage() { return message; } - public Integer getCode() { - return code; - } - public ServiceException setMessage(String message) { this.message = message; return this; diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/RegexPatternPoolFactory.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/RegexPatternPoolFactory.java new file mode 100644 index 000000000..fd907d2c2 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/RegexPatternPoolFactory.java @@ -0,0 +1,52 @@ +package org.dromara.common.core.factory; + +import cn.hutool.core.lang.PatternPool; +import org.dromara.common.core.constant.RegexConstants; + +import java.util.regex.Pattern; + +/** + * 正则表达式模式池工厂 + *

初始化的时候将正则表达式加入缓存池当中

+ *

提高正则表达式的性能,避免重复编译相同的正则表达式

+ * + * @author 21001 + */ +public class RegexPatternPoolFactory extends PatternPool { + + /** + * 字典类型必须以字母开头,且只能为(小写字母,数字,下滑线) + */ + public static final Pattern DICTIONARY_TYPE = get(RegexConstants.DICTIONARY_TYPE); + + /** + * 身份证号码(后6位) + */ + public static final Pattern ID_CARD_LAST_6 = get(RegexConstants.ID_CARD_LAST_6); + + /** + * QQ号码 + */ + public static final Pattern QQ_NUMBER = get(RegexConstants.QQ_NUMBER); + + /** + * 邮政编码 + */ + public static final Pattern POSTAL_CODE = get(RegexConstants.POSTAL_CODE); + + /** + * 注册账号 + */ + public static final Pattern ACCOUNT = get(RegexConstants.ACCOUNT); + + /** + * 密码:包含至少8个字符,包括大写字母、小写字母、数字和特殊字符 + */ + public static final Pattern PASSWORD = get(RegexConstants.PASSWORD); + + /** + * 通用状态(0表示正常,1表示停用) + */ + public static final Pattern STATUS = get(RegexConstants.STATUS); + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java index d6b312a64..f8f155a7b 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java @@ -23,4 +23,20 @@ public interface UserService { */ String selectNicknameById(Long userId); + /** + * 通过用户ID查询用户手机号 + * + * @param userId 用户id + * @return 用户手机号 + */ + String selectPhonenumberById(Long userId); + + /** + * 通过用户ID查询用户邮箱 + * + * @param userId 用户id + * @return 用户邮箱 + */ + String selectEmailById(Long userId); + } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/SpringUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/SpringUtils.java index ab5053931..e58c394ac 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/SpringUtils.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/SpringUtils.java @@ -3,7 +3,9 @@ package org.dromara.common.core.utils; import cn.hutool.extra.spring.SpringUtil; import org.springframework.aop.framework.AopContext; import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.boot.autoconfigure.thread.Threading; import org.springframework.context.ApplicationContext; +import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; /** @@ -59,4 +61,8 @@ public final class SpringUtils extends SpringUtil { return getApplicationContext(); } + public static boolean isVirtual() { + return Threading.VIRTUAL.isActive(getBean(Environment.class)); + } + } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StringUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StringUtils.java index 5e4db50e3..dd6ebb119 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StringUtils.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StringUtils.java @@ -22,6 +22,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils { public static final String SEPARATOR = ","; + public static final String SLASH = "/"; + /** * 获取参数不为空值 * diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexUtils.java new file mode 100644 index 000000000..b8b12d43c --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexUtils.java @@ -0,0 +1,30 @@ +package org.dromara.common.core.utils.regex; + + +import cn.hutool.core.util.ReUtil; +import org.dromara.common.core.constant.RegexConstants; + +/** + * 正则相关工具类 + * + * @author Feng + */ +public final class RegexUtils extends ReUtil { + + /** + * 从输入字符串中提取匹配的部分,如果没有匹配则返回默认值 + * + * @param input 要提取的输入字符串 + * @param regex 用于匹配的正则表达式,可以使用 {@link RegexConstants} 中定义的常量 + * @param defaultInput 如果没有匹配时返回的默认值 + * @return 如果找到匹配的部分,则返回匹配的部分,否则返回默认值 + */ + public static String extractFromString(String input, String regex, String defaultInput) { + try { + return ReUtil.get(regex, input, 1); + } catch (Exception e) { + return defaultInput; + } + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexValidator.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexValidator.java new file mode 100644 index 000000000..c0dda2020 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexValidator.java @@ -0,0 +1,105 @@ +package org.dromara.common.core.utils.regex; + +import cn.hutool.core.exceptions.ValidateException; +import cn.hutool.core.lang.Validator; +import org.dromara.common.core.factory.RegexPatternPoolFactory; + +import java.util.regex.Pattern; + +/** + * 正则字段校验器 + * 主要验证字段非空、是否为满足指定格式等 + * + * @author Feng + */ +public class RegexValidator extends Validator { + + /** + * 字典类型必须以字母开头,且只能为(小写字母,数字,下滑线) + */ + public static final Pattern DICTIONARY_TYPE = RegexPatternPoolFactory.DICTIONARY_TYPE; + + /** + * 身份证号码(后6位) + */ + public static final Pattern ID_CARD_LAST_6 = RegexPatternPoolFactory.ID_CARD_LAST_6; + + /** + * QQ号码 + */ + public static final Pattern QQ_NUMBER = RegexPatternPoolFactory.QQ_NUMBER; + + /** + * 邮政编码 + */ + public static final Pattern POSTAL_CODE = RegexPatternPoolFactory.POSTAL_CODE; + + /** + * 注册账号 + */ + public static final Pattern ACCOUNT = RegexPatternPoolFactory.ACCOUNT; + + /** + * 密码:包含至少8个字符,包括大写字母、小写字母、数字和特殊字符 + */ + public static final Pattern PASSWORD = RegexPatternPoolFactory.PASSWORD; + + /** + * 通用状态(0表示正常,1表示停用) + */ + public static final Pattern STATUS = RegexPatternPoolFactory.STATUS; + + + /** + * 检查输入的账号是否匹配预定义的规则 + * + * @param value 要验证的账号 + * @return 如果账号符合规则,返回 true;否则,返回 false。 + */ + public static boolean isAccount(CharSequence value) { + return isMatchRegex(ACCOUNT, value); + } + + /** + * 验证输入的账号是否符合规则,如果不符合,则抛出 ValidateException 异常 + * + * @param value 要验证的账号 + * @param errorMsg 验证失败时抛出的异常消息 + * @param CharSequence 的子类型 + * @return 如果验证通过,返回输入的账号 + * @throws ValidateException 如果验证失败 + */ + public static T validateAccount(T value, String errorMsg) throws ValidateException { + if (!isAccount(value)) { + throw new ValidateException(errorMsg); + } + return value; + } + + /** + * 检查输入的状态是否匹配预定义的规则 + * + * @param value 要验证的状态 + * @return 如果状态符合规则,返回 true;否则,返回 false。 + */ + public static boolean isStatus(CharSequence value) { + return isMatchRegex(STATUS, value); + } + + /** + * 验证输入的状态是否符合规则,如果不符合,则抛出 ValidateException 异常 + * + * @param value 要验证的状态 + * @param errorMsg 验证失败时抛出的异常消息 + * @param CharSequence 的子类型 + * @return 如果验证通过,返回输入的状态 + * @throws ValidateException 如果验证失败 + */ + public static T validateStatus(T value, String errorMsg) throws ValidateException { + if (!isStatus(value)) { + throw new ValidateException(errorMsg); + } + return value; + } + +} diff --git a/ruoyi-common/ruoyi-common-encrypt/pom.xml b/ruoyi-common/ruoyi-common-encrypt/pom.xml index df3222bee..ed4910ef0 100644 --- a/ruoyi-common/ruoyi-common-encrypt/pom.xml +++ b/ruoyi-common/ruoyi-common-encrypt/pom.xml @@ -22,11 +22,6 @@ ruoyi-common-core - - org.mybatis.spring.boot - mybatis-spring-boot-starter - - org.bouncycastle bcprov-jdk15to18 @@ -42,6 +37,18 @@ spring-webmvc + + com.baomidou + mybatis-plus-spring-boot3-starter + true + + + org.mybatis + mybatis-spring + + + + diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/EncryptorAutoConfiguration.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/EncryptorAutoConfiguration.java index e988a3a2c..fbc4e52de 100644 --- a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/EncryptorAutoConfiguration.java +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/EncryptorAutoConfiguration.java @@ -1,5 +1,8 @@ package org.dromara.common.encrypt.config; +import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration; +import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties; +import lombok.extern.slf4j.Slf4j; import org.dromara.common.encrypt.core.EncryptorManager; import org.dromara.common.encrypt.interceptor.MybatisDecryptInterceptor; import org.dromara.common.encrypt.interceptor.MybatisEncryptInterceptor; @@ -16,17 +19,18 @@ import org.springframework.context.annotation.Bean; * @author 老马 * @version 4.6.0 */ -@AutoConfiguration +@AutoConfiguration(after = MybatisPlusAutoConfiguration.class) @EnableConfigurationProperties(EncryptorProperties.class) @ConditionalOnProperty(value = "mybatis-encryptor.enable", havingValue = "true") +@Slf4j public class EncryptorAutoConfiguration { @Autowired private EncryptorProperties properties; @Bean - public EncryptorManager encryptorManager() { - return new EncryptorManager(); + public EncryptorManager encryptorManager(MybatisPlusProperties mybatisPlusProperties) { + return new EncryptorManager(mybatisPlusProperties.getTypeAliasesPackage()); } @Bean @@ -38,4 +42,8 @@ public class EncryptorAutoConfiguration { public MybatisDecryptInterceptor mybatisDecryptInterceptor(EncryptorManager encryptorManager) { return new MybatisDecryptInterceptor(encryptorManager, properties); } + } + + + diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptorManager.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptorManager.java index 498b4b85b..a6d3cf9ce 100644 --- a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptorManager.java +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptorManager.java @@ -1,14 +1,23 @@ package org.dromara.common.encrypt.core; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ReflectUtil; +import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.io.Resources; +import org.dromara.common.core.utils.StringUtils; import org.dromara.common.encrypt.annotation.EncryptField; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.core.type.ClassMetadata; +import org.springframework.core.type.classreading.CachingMetadataReaderFactory; +import org.springframework.util.ClassUtils; import java.lang.reflect.Field; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; @@ -19,6 +28,7 @@ import java.util.stream.Collectors; * @version 4.6.0 */ @Slf4j +@NoArgsConstructor public class EncryptorManager { /** @@ -31,25 +41,24 @@ public class EncryptorManager { */ Map, Set> fieldCache = new ConcurrentHashMap<>(); + /** + * 构造方法传入类加密字段缓存 + * + * @param typeAliasesPackage 实体类包 + */ + public EncryptorManager(String typeAliasesPackage) { + scanEncryptClasses(typeAliasesPackage); + } + + /** * 获取类加密字段缓存 */ public Set getFieldCache(Class sourceClazz) { - return fieldCache.computeIfAbsent(sourceClazz, clazz -> { - Set fieldSet = new HashSet<>(); - while (clazz != null) { - Field[] fields = clazz.getDeclaredFields(); - fieldSet.addAll(Arrays.asList(fields)); - clazz = clazz.getSuperclass(); - } - fieldSet = fieldSet.stream().filter(field -> - field.isAnnotationPresent(EncryptField.class) && field.getType() == String.class) - .collect(Collectors.toSet()); - for (Field field : fieldSet) { - field.setAccessible(true); - } - return fieldSet; - }); + if (ObjectUtil.isNotNull(fieldCache)) { + return fieldCache.get(sourceClazz); + } + return null; } /** @@ -97,4 +106,53 @@ public class EncryptorManager { return encryptor.decrypt(value); } + /** + * 通过 typeAliasesPackage 设置的扫描包 扫描缓存实体 + */ + private void scanEncryptClasses(String typeAliasesPackage) { + PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); + CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory(); + String[] packagePatternArray = StringUtils.splitPreserveAllTokens(typeAliasesPackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); + String classpath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX; + try { + for (String packagePattern : packagePatternArray) { + String path = ClassUtils.convertClassNameToResourcePath(packagePattern); + Resource[] resources = resolver.getResources(classpath + path + "/*.class"); + for (Resource resource : resources) { + ClassMetadata classMetadata = factory.getMetadataReader(resource).getClassMetadata(); + Class clazz = Resources.classForName(classMetadata.getClassName()); + Set encryptFieldSet = getEncryptFieldSetFromClazz(clazz); + if (CollUtil.isNotEmpty(encryptFieldSet)) { + fieldCache.put(clazz, encryptFieldSet); + } + } + } + } catch (Exception e) { + log.error("初始化数据安全缓存时出错:{}", e.getMessage()); + } + } + + /** + * 获得一个类的加密字段集合 + */ + private Set getEncryptFieldSetFromClazz(Class clazz) { + Set fieldSet = new HashSet<>(); + // 判断clazz如果是接口,内部类,匿名类就直接返回 + if (clazz.isInterface() || clazz.isMemberClass() || clazz.isAnonymousClass()) { + return fieldSet; + } + while (clazz != null) { + Field[] fields = clazz.getDeclaredFields(); + fieldSet.addAll(Arrays.asList(fields)); + clazz = clazz.getSuperclass(); + } + fieldSet = fieldSet.stream().filter(field -> + field.isAnnotationPresent(EncryptField.class) && field.getType() == String.class) + .collect(Collectors.toSet()); + for (Field field : fieldSet) { + field.setAccessible(true); + } + return fieldSet; + } + } diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/CryptoFilter.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/CryptoFilter.java index b43881a22..98351321d 100644 --- a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/CryptoFilter.java +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/CryptoFilter.java @@ -11,14 +11,12 @@ import org.dromara.common.core.utils.StringUtils; import org.dromara.common.encrypt.annotation.ApiEncrypt; import org.dromara.common.encrypt.properties.ApiDecryptProperties; import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.HandlerExecutionChain; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; import java.io.IOException; -import java.io.PrintWriter; /** @@ -37,42 +35,38 @@ public class CryptoFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest servletRequest = (HttpServletRequest) request; HttpServletResponse servletResponse = (HttpServletResponse) response; - - boolean responseFlag = false; + // 获取加密注解 + ApiEncrypt apiEncrypt = this.getApiEncryptAnnotation(servletRequest); + boolean responseFlag = apiEncrypt != null && apiEncrypt.response(); ServletRequest requestWrapper = null; ServletResponse responseWrapper = null; EncryptResponseBodyWrapper responseBodyWrapper = null; - // 是否为 json 请求 - if (StringUtils.startsWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE)) { - // 是否为 put 或者 post 请求 - if (HttpMethod.PUT.matches(servletRequest.getMethod()) || HttpMethod.POST.matches(servletRequest.getMethod())) { - // 是否存在加密标头 - String headerValue = servletRequest.getHeader(properties.getHeaderFlag()); - // 获取加密注解 - ApiEncrypt apiEncrypt = this.getApiEncryptAnnotation(servletRequest); - responseFlag = apiEncrypt != null && apiEncrypt.response(); - if (StringUtils.isNotBlank(headerValue)) { - // 请求解密 - requestWrapper = new DecryptRequestBodyWrapper(servletRequest, properties.getPrivateKey(), properties.getHeaderFlag()); - } else { - // 是否有注解,有就报错,没有放行 - if (ObjectUtil.isNotNull(apiEncrypt)) { - HandlerExceptionResolver exceptionResolver = SpringUtils.getBean("handlerExceptionResolver", HandlerExceptionResolver.class); - exceptionResolver.resolveException( - servletRequest, servletResponse, null, - new ServiceException("没有访问权限,请联系管理员授权", HttpStatus.FORBIDDEN)); - return; - } - } - // 判断是否响应加密 - if (responseFlag) { - responseBodyWrapper = new EncryptResponseBodyWrapper(servletResponse); - responseWrapper = responseBodyWrapper; + // 是否为 put 或者 post 请求 + if (HttpMethod.PUT.matches(servletRequest.getMethod()) || HttpMethod.POST.matches(servletRequest.getMethod())) { + // 是否存在加密标头 + String headerValue = servletRequest.getHeader(properties.getHeaderFlag()); + if (StringUtils.isNotBlank(headerValue)) { + // 请求解密 + requestWrapper = new DecryptRequestBodyWrapper(servletRequest, properties.getPrivateKey(), properties.getHeaderFlag()); + } else { + // 是否有注解,有就报错,没有放行 + if (ObjectUtil.isNotNull(apiEncrypt)) { + HandlerExceptionResolver exceptionResolver = SpringUtils.getBean("handlerExceptionResolver", HandlerExceptionResolver.class); + exceptionResolver.resolveException( + servletRequest, servletResponse, null, + new ServiceException("没有访问权限,请联系管理员授权", HttpStatus.FORBIDDEN)); + return; } } } + // 判断是否响应加密 + if (responseFlag) { + responseBodyWrapper = new EncryptResponseBodyWrapper(servletResponse); + responseWrapper = responseBodyWrapper; + } + chain.doFilter( ObjectUtil.defaultIfNull(requestWrapper, request), ObjectUtil.defaultIfNull(responseWrapper, response)); diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisDecryptInterceptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisDecryptInterceptor.java index 7c2508f86..460aa360e 100644 --- a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisDecryptInterceptor.java +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisDecryptInterceptor.java @@ -73,7 +73,11 @@ public class MybatisDecryptInterceptor implements Interceptor { list.forEach(this::decryptHandler); return; } + // 不在缓存中的类,就是没有加密注解的类(当然也有可能是typeAliasesPackage写错) Set fields = encryptorManager.getFieldCache(sourceObject.getClass()); + if(ObjectUtil.isNull(fields)){ + return; + } try { for (Field field : fields) { field.set(sourceObject, this.decryptField(Convert.toStr(field.get(sourceObject)), field)); diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisEncryptInterceptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisEncryptInterceptor.java index 152f7db40..bcc2f4c9f 100644 --- a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisEncryptInterceptor.java +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisEncryptInterceptor.java @@ -82,7 +82,11 @@ public class MybatisEncryptInterceptor implements Interceptor { list.forEach(this::encryptHandler); return; } + // 不在缓存中的类,就是没有加密注解的类(当然也有可能是typeAliasesPackage写错) Set fields = encryptorManager.getFieldCache(sourceObject.getClass()); + if(ObjectUtil.isNull(fields)){ + return; + } try { for (Field field : fields) { field.set(sourceObject, this.encryptField(Convert.toStr(field.get(sourceObject)), field)); diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/CellMerge.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/CellMerge.java index bbdaaa14d..6b9211b53 100644 --- a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/CellMerge.java +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/CellMerge.java @@ -21,4 +21,9 @@ public @interface CellMerge { */ int index() default -1; + /** + * 合并需要依赖的其他字段名称 + */ + String[] mergeBy() default {}; + } diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java index bcb5be767..7c0a48b9a 100644 --- a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java @@ -1,8 +1,12 @@ package org.dromara.common.excel.core; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ReflectUtil; +import cn.hutool.core.util.StrUtil; import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.write.handler.WorkbookWriteHandler; +import com.alibaba.excel.write.handler.context.WorkbookWriteHandlerContext; import com.alibaba.excel.write.merge.AbstractMergeStrategy; import lombok.AllArgsConstructor; import lombok.Data; @@ -15,10 +19,7 @@ import org.dromara.common.core.utils.reflect.ReflectUtils; import org.dromara.common.excel.annotation.CellMerge; import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; /** * 列值重复合并策略 @@ -26,7 +27,7 @@ import java.util.Map; * @author Lion Li */ @Slf4j -public class CellMergeStrategy extends AbstractMergeStrategy { +public class CellMergeStrategy extends AbstractMergeStrategy implements WorkbookWriteHandler { private final List cellList; private final boolean hasTitle; @@ -41,17 +42,28 @@ public class CellMergeStrategy extends AbstractMergeStrategy { @Override protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) { - // judge the list is not null - if (CollUtil.isNotEmpty(cellList)) { - // the judge is necessary - if (cell.getRowIndex() == rowIndex && cell.getColumnIndex() == 0) { - for (CellRangeAddress item : cellList) { - sheet.addMergedRegion(item); + //单元格写入了,遍历合并区域,如果该Cell在区域内,但非首行,则清空 + final int rowIndex = cell.getRowIndex(); + if (CollUtil.isNotEmpty(cellList)){ + for (CellRangeAddress cellAddresses : cellList) { + final int firstRow = cellAddresses.getFirstRow(); + if (cellAddresses.isInRange(cell) && rowIndex != firstRow){ + cell.setBlank(); } } } } + @Override + public void afterWorkbookDispose(final WorkbookWriteHandlerContext context) { + //当前表格写完后,统一写入 + if (CollUtil.isNotEmpty(cellList)){ + for (CellRangeAddress item : cellList) { + context.getWriteContext().writeSheetHolder().getSheet().addMergedRegion(item); + } + } + } + @SneakyThrows private List handle(List list, boolean hasTitle) { List cellList = new ArrayList<>(); @@ -93,35 +105,15 @@ public class CellMergeStrategy extends AbstractMergeStrategy { // 空值跳过不合并 continue; } + if (!cellValue.equals(val)) { - if (i - repeatCell.getCurrent() > 1) { + if ((i - repeatCell.getCurrent() > 1) && isMerge(list, i, field)) { cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex - 1, colNum, colNum)); } map.put(field, new RepeatCell(val, i)); - } else if (j == 0) { - if (i == list.size() - 1) { - if (i > repeatCell.getCurrent()) { - cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex, colNum, colNum)); - } - } - } else { - // 判断前面的是否合并了 - RepeatCell firstCell = map.get(mergeFields.get(0)); - if (repeatCell.getCurrent() != firstCell.getCurrent()) { - if (i == list.size() - 1) { - if (i > repeatCell.getCurrent()) { - cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex, colNum, colNum)); - } - } else if (repeatCell.getCurrent() < firstCell.getCurrent()) { - if (i - repeatCell.getCurrent() > 1) { - cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex - 1, colNum, colNum)); - } - map.put(field, new RepeatCell(val, i)); - } - } else if (i == list.size() - 1) { - if (i > repeatCell.getCurrent()) { - cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex, colNum, colNum)); - } + } else if (i == list.size() - 1) { + if (i > repeatCell.getCurrent() && isMerge(list, i, field)) { + cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex, colNum, colNum)); } } } @@ -130,6 +122,24 @@ public class CellMergeStrategy extends AbstractMergeStrategy { return cellList; } + private boolean isMerge(List list, int i, Field field) { + boolean isMerge = true; + CellMerge cm = field.getAnnotation(CellMerge.class); + final String[] mergeBy = cm.mergeBy(); + if (StrUtil.isAllNotBlank(mergeBy)) { + //比对当前list(i)和list(i - 1)的各个属性值一一比对 如果全为真 则为真 + for (String fieldName : mergeBy) { + final Object valCurrent = ReflectUtil.getFieldValue(list.get(i), fieldName); + final Object valPre = ReflectUtil.getFieldValue(list.get(i - 1), fieldName); + if (!Objects.equals(valPre, valCurrent)) { + //依赖字段如有任一不等值,则标记为不可合并 + isMerge = false; + } + } + } + return isMerge; + } + @Data @AllArgsConstructor static class RepeatCell { diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java index 3b791ea54..b3f68ed1e 100644 --- a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java @@ -20,6 +20,7 @@ import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.service.DictService; import org.dromara.common.core.utils.SpringUtils; import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; import org.dromara.common.excel.annotation.ExcelDictFormat; import org.dromara.common.excel.annotation.ExcelEnumFormat; @@ -99,15 +100,16 @@ public class ExcelDownHandler implements SheetWriteHandler { ExcelDictFormat format = field.getDeclaredAnnotation(ExcelDictFormat.class); String dictType = format.dictType(); String converterExp = format.readConverterExp(); - if (StrUtil.isNotBlank(dictType)) { + if (StringUtils.isNotBlank(dictType)) { // 如果传递了字典名,则依据字典建立下拉 Collection values = Optional.ofNullable(dictService.getAllDictByDictType(dictType)) .orElseThrow(() -> new ServiceException(String.format("字典 %s 不存在", dictType))) .values(); options = new ArrayList<>(values); - } else if (StrUtil.isNotBlank(converterExp)) { + } else if (StringUtils.isNotBlank(converterExp)) { // 如果指定了确切的值,则直接解析确切的值 - options = StrUtil.split(converterExp, format.separator(), true, true); + List strList = StringUtils.splitList(converterExp, format.separator()); + options = StreamUtils.toList(strList, s -> StringUtils.split(s, "=")[1]); } } else if (field.isAnnotationPresent(ExcelEnumFormat.class)) { // 否则如果指定了@ExcelEnumFormat,则使用枚举的逻辑 diff --git a/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/aspectj/RepeatSubmitAspect.java b/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/aspectj/RepeatSubmitAspect.java index 016fe0fb1..5a27e9189 100644 --- a/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/aspectj/RepeatSubmitAspect.java +++ b/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/aspectj/RepeatSubmitAspect.java @@ -4,6 +4,13 @@ import cn.dev33.satoken.SaManager; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.crypto.SecureUtil; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; import org.dromara.common.core.constant.GlobalConstants; import org.dromara.common.core.domain.R; import org.dromara.common.core.exception.ServiceException; @@ -13,13 +20,6 @@ import org.dromara.common.core.utils.StringUtils; import org.dromara.common.idempotent.annotation.RepeatSubmit; import org.dromara.common.json.utils.JsonUtils; import org.dromara.common.redis.utils.RedisUtils; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.aspectj.lang.JoinPoint; -import org.aspectj.lang.annotation.AfterReturning; -import org.aspectj.lang.annotation.AfterThrowing; -import org.aspectj.lang.annotation.Aspect; -import org.aspectj.lang.annotation.Before; import org.springframework.validation.BindingResult; import org.springframework.web.multipart.MultipartFile; @@ -127,7 +127,7 @@ public class RepeatSubmitAspect { public boolean isFilterObject(final Object o) { Class clazz = o.getClass(); if (clazz.isArray()) { - return clazz.getComponentType().isAssignableFrom(MultipartFile.class); + return MultipartFile.class.isAssignableFrom(clazz.getComponentType()); } else if (Collection.class.isAssignableFrom(clazz)) { Collection collection = (Collection) o; for (Object value : collection) { diff --git a/ruoyi-common/ruoyi-common-job/pom.xml b/ruoyi-common/ruoyi-common-job/pom.xml index 1a6e729b4..47bfc432e 100644 --- a/ruoyi-common/ruoyi-common-job/pom.xml +++ b/ruoyi-common/ruoyi-common-job/pom.xml @@ -38,6 +38,20 @@ powerjob-official-processors + + + com.aizuda + easy-retry-client-starter + + + com.aizuda + easy-retry-client-core + + + com.aizuda + easy-retry-client-job-core + + org.projectlombok lombok diff --git a/ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/EasyRetryConfig.java b/ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/EasyRetryConfig.java new file mode 100644 index 000000000..13f36dc32 --- /dev/null +++ b/ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/EasyRetryConfig.java @@ -0,0 +1,37 @@ +package org.dromara.common.job.config; + +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.classic.spi.ILoggingEvent; +import com.aizuda.easy.retry.client.common.appender.EasyRetryLogbackAppender; +import com.aizuda.easy.retry.client.common.event.EasyRetryStartingEvent; +import com.aizuda.easy.retry.client.starter.EnableEasyRetry; +import org.slf4j.LoggerFactory; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.EnableScheduling; + +/** + * 启动定时任务 + * + * @author dhb52 + * @since 2024/3/12 + */ +@AutoConfiguration +@ConditionalOnProperty(prefix = "easy-retry", name = "enabled", havingValue = "true") +@EnableScheduling +@EnableEasyRetry(group = "${easy-retry.group-name}") +public class EasyRetryConfig { + + @EventListener(EasyRetryStartingEvent.class) + public void onStarting(EasyRetryStartingEvent event) { + LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); + EasyRetryLogbackAppender ca = new EasyRetryLogbackAppender<>(); + ca.setName("easy_log_appender"); + ca.start(); + Logger rootLogger = lc.getLogger(Logger.ROOT_LOGGER_NAME); + rootLogger.addAppender(ca); + } + +} diff --git a/ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/PowerJobConfig.java b/ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/PowerJobConfig.java index 67208c0e5..9835c7f6e 100644 --- a/ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/PowerJobConfig.java +++ b/ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/PowerJobConfig.java @@ -1,8 +1,8 @@ package org.dromara.common.job.config; +import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableScheduling; import tech.powerjob.worker.PowerJobWorker; @@ -11,7 +11,7 @@ import tech.powerjob.worker.PowerJobWorker; * @author yhan219 * @since 2023/6/2 */ -@Configuration +@AutoConfiguration @ConditionalOnBean(PowerJobWorker.class) @ConditionalOnProperty(prefix = "powerjob.worker", name = "enabled", havingValue = "true") @EnableScheduling diff --git a/ruoyi-common/ruoyi-common-job/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-job/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..2e3dc3209 --- /dev/null +++ b/ruoyi-common/ruoyi-common-job/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,2 @@ +org.dromara.common.job.config.PowerJobConfig +org.dromara.common.job.config.EasyRetryConfig diff --git a/ruoyi-common/ruoyi-common-log/pom.xml b/ruoyi-common/ruoyi-common-log/pom.xml index 28bd5304a..1e2b33b44 100644 --- a/ruoyi-common/ruoyi-common-log/pom.xml +++ b/ruoyi-common/ruoyi-common-log/pom.xml @@ -27,11 +27,6 @@ ruoyi-common-json - - com.alibaba - transmittable-thread-local - - diff --git a/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java index e98f4f7fa..87240729c 100644 --- a/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java +++ b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java @@ -4,16 +4,6 @@ import cn.hutool.core.lang.Dict; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjectUtil; -import com.alibaba.ttl.TransmittableThreadLocal; -import org.dromara.common.core.domain.model.LoginUser; -import org.dromara.common.core.utils.ServletUtils; -import org.dromara.common.core.utils.SpringUtils; -import org.dromara.common.core.utils.StringUtils; -import org.dromara.common.json.utils.JsonUtils; -import org.dromara.common.log.annotation.Log; -import org.dromara.common.log.enums.BusinessStatus; -import org.dromara.common.log.event.OperLogEvent; -import org.dromara.common.satoken.utils.LoginHelper; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; @@ -23,6 +13,15 @@ import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.utils.ServletUtils; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessStatus; +import org.dromara.common.log.event.OperLogEvent; +import org.dromara.common.satoken.utils.LoginHelper; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.http.HttpMethod; import org.springframework.validation.BindingResult; @@ -49,9 +48,9 @@ public class LogAspect { /** - * 计算操作消耗时间 + * 计时 key */ - private static final ThreadLocal TIME_THREADLOCAL = new TransmittableThreadLocal<>(); + private static final ThreadLocal KEY_CACHE = new ThreadLocal<>(); /** * 处理请求前执行 @@ -59,7 +58,7 @@ public class LogAspect { @Before(value = "@annotation(controllerLog)") public void boBefore(JoinPoint joinPoint, Log controllerLog) { StopWatch stopWatch = new StopWatch(); - TIME_THREADLOCAL.set(stopWatch); + KEY_CACHE.set(stopWatch); stopWatch.start(); } @@ -112,7 +111,7 @@ public class LogAspect { // 处理设置注解上的参数 getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult); // 设置消耗时间 - StopWatch stopWatch = TIME_THREADLOCAL.get(); + StopWatch stopWatch = KEY_CACHE.get(); stopWatch.stop(); operLog.setCostTime(stopWatch.getTime()); // 发布事件保存数据库 @@ -122,7 +121,7 @@ public class LogAspect { log.error("异常信息:{}", exp.getMessage()); exp.printStackTrace(); } finally { - TIME_THREADLOCAL.remove(); + KEY_CACHE.remove(); } } @@ -204,7 +203,7 @@ public class LogAspect { public boolean isFilterObject(final Object o) { Class clazz = o.getClass(); if (clazz.isArray()) { - return clazz.getComponentType().isAssignableFrom(MultipartFile.class); + return MultipartFile.class.isAssignableFrom(clazz.getComponentType()); } else if (Collection.class.isAssignableFrom(clazz)) { Collection collection = (Collection) o; for (Object value : collection) { diff --git a/ruoyi-common/ruoyi-common-mybatis/pom.xml b/ruoyi-common/ruoyi-common-mybatis/pom.xml index 07b486c92..44b11ef5e 100644 --- a/ruoyi-common/ruoyi-common-mybatis/pom.xml +++ b/ruoyi-common/ruoyi-common-mybatis/pom.xml @@ -39,7 +39,7 @@ com.baomidou - mybatis-plus-boot-starter + mybatis-plus-spring-boot3-starter org.mybatis diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java index 1689e3cdf..495daf10a 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java @@ -1,34 +1,29 @@ package org.dromara.common.mybatis.config; import cn.hutool.core.net.NetUtil; -import com.baomidou.mybatisplus.autoconfigure.DdlApplicationRunner; -import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator; import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; -import com.baomidou.mybatisplus.extension.ddl.IDdl; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; import org.dromara.common.core.factory.YmlPropertySourceFactory; +import org.dromara.common.core.utils.SpringUtils; import org.dromara.common.mybatis.handler.InjectionMetaObjectHandler; import org.dromara.common.mybatis.interceptor.PlusDataPermissionInterceptor; import org.mybatis.spring.annotation.MapperScan; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.beans.BeansException; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.PropertySource; import org.springframework.transaction.annotation.EnableTransactionManagement; -import java.util.List; - /** * mybatis-plus配置类(下方注释有插件介绍) * * @author Lion Li */ @EnableTransactionManagement(proxyTargetClass = true) -@AutoConfiguration(before = MybatisPlusAutoConfiguration.class) @MapperScan("${mybatis-plus.mapperPackage}") @PropertySource(value = "classpath:common-mybatis.yml", factory = YmlPropertySourceFactory.class) public class MybatisPlusConfig { @@ -36,6 +31,12 @@ public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + // 多租户插件 必须放到第一位 + try { + TenantLineInnerInterceptor tenant = SpringUtils.getBean(TenantLineInnerInterceptor.class); + interceptor.addInnerInterceptor(tenant); + } catch (BeansException ignore) { + } // 数据权限处理 interceptor.addInnerInterceptor(dataPermissionInterceptor()); // 分页插件 @@ -49,7 +50,7 @@ public class MybatisPlusConfig { * 数据权限拦截器 */ public PlusDataPermissionInterceptor dataPermissionInterceptor() { - return new PlusDataPermissionInterceptor(); + return new PlusDataPermissionInterceptor(SpringUtils.getProperty("mybatis-plus.mapperPackage")); } /** @@ -108,9 +109,4 @@ public class MybatisPlusConfig { * https://baomidou.com/pages/2a45ff/ */ - @Bean - public DdlApplicationRunner ddlApplicationRunner(@Autowired(required = false) List ddlList) { - return new DdlApplicationRunner(ddlList); - } - } diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/mapper/BaseMapperPlus.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/mapper/BaseMapperPlus.java index 9018a791c..08723f608 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/mapper/BaseMapperPlus.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/mapper/BaseMapperPlus.java @@ -35,7 +35,6 @@ public interface BaseMapperPlus extends BaseMapper { Log log = LogFactory.getLog(BaseMapperPlus.class); default Class currentVoClass() { - GenericTypeUtils.resolveTypeArguments(this.getClass(), BaseMapperPlus.class); return (Class) GenericTypeUtils.resolveTypeArguments(this.getClass(), BaseMapperPlus.class)[1]; } @@ -145,11 +144,22 @@ public interface BaseMapperPlus extends BaseMapper { return selectVoOne(wrapper, this.currentVoClass()); } + default V selectVoOne(Wrapper wrapper, boolean throwEx) { + return selectVoOne(wrapper, this.currentVoClass(), throwEx); + } + /** * 根据 entity 条件,查询一条记录 */ default C selectVoOne(Wrapper wrapper, Class voClass) { - T obj = this.selectOne(wrapper); + return selectVoOne(wrapper, voClass, true); + } + + /** + * 根据 entity 条件,查询一条记录 + */ + default C selectVoOne(Wrapper wrapper, Class voClass, boolean throwEx) { + T obj = this.selectOne(wrapper, throwEx); if (ObjectUtil.isNull(obj)) { return null; } diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/PageQuery.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/PageQuery.java index 8ef4a578d..40b7530e5 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/PageQuery.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/PageQuery.java @@ -111,4 +111,8 @@ public class PageQuery implements Serializable { return list; } + public Integer getFirstNum() { + return (pageNum - 1) * pageSize; + } + } diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java index 63653de3c..a66908f09 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java @@ -29,16 +29,17 @@ public class InjectionMetaObjectHandler implements MetaObjectHandler { ? baseEntity.getCreateTime() : new Date(); baseEntity.setCreateTime(current); baseEntity.setUpdateTime(current); - LoginUser loginUser = getLoginUser(); - if (ObjectUtil.isNotNull(loginUser)) { - Long userId = ObjectUtil.isNotNull(baseEntity.getCreateBy()) - ? baseEntity.getCreateBy() : loginUser.getUserId(); - // 当前已登录 且 创建人为空 则填充 - baseEntity.setCreateBy(userId); - // 当前已登录 且 更新人为空 则填充 - baseEntity.setUpdateBy(userId); - baseEntity.setCreateDept(ObjectUtil.isNotNull(baseEntity.getCreateDept()) - ? baseEntity.getCreateDept() : loginUser.getDeptId()); + if (ObjectUtil.isNull(baseEntity.getCreateBy())) { + LoginUser loginUser = getLoginUser(); + if (ObjectUtil.isNotNull(loginUser)) { + Long userId = loginUser.getUserId(); + // 当前已登录 且 创建人为空 则填充 + baseEntity.setCreateBy(userId); + // 当前已登录 且 更新人为空 则填充 + baseEntity.setUpdateBy(userId); + baseEntity.setCreateDept(ObjectUtil.isNotNull(baseEntity.getCreateDept()) + ? baseEntity.getCreateDept() : loginUser.getDeptId()); + } } } } catch (Exception e) { @@ -53,11 +54,12 @@ public class InjectionMetaObjectHandler implements MetaObjectHandler { Date current = new Date(); // 更新时间填充(不管为不为空) baseEntity.setUpdateTime(current); - LoginUser loginUser = getLoginUser(); // 当前已登录 更新人填充(不管为不为空) - if (ObjectUtil.isNotNull(loginUser)) { - baseEntity.setUpdateBy(loginUser.getUserId()); + Long userId = LoginHelper.getUserId(); + if (ObjectUtil.isNotNull(userId)) { + baseEntity.setUpdateBy(userId); } + } } catch (Exception e) { throw new ServiceException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED); diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/MybatisExceptionHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/MybatisExceptionHandler.java index c517fa728..ec3ee0df7 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/MybatisExceptionHandler.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/MybatisExceptionHandler.java @@ -2,6 +2,7 @@ package org.dromara.common.mybatis.handler; import org.dromara.common.core.domain.R; import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.utils.StringUtils; import org.mybatis.spring.MyBatisSystemException; import org.springframework.dao.DuplicateKeyException; import org.springframework.web.bind.annotation.ExceptionHandler; @@ -35,7 +36,7 @@ public class MybatisExceptionHandler { public R handleCannotFindDataSourceException(MyBatisSystemException e, HttpServletRequest request) { String requestURI = request.getRequestURI(); String message = e.getMessage(); - if ("CannotFindDataSourceException".contains(message)) { + if (StringUtils.contains("CannotFindDataSourceException", message)) { log.error("请求地址'{}', 未找到数据源", requestURI); return R.fail("未找到数据源,请联系管理员确认"); } diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java index 6ddaa243c..7d7fd84a9 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java @@ -2,7 +2,6 @@ package org.dromara.common.mybatis.handler; import cn.hutool.core.annotation.AnnotationUtil; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ClassUtil; import cn.hutool.core.util.ObjectUtil; import lombok.extern.slf4j.Slf4j; import net.sf.jsqlparser.JSQLParserException; @@ -10,6 +9,7 @@ import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.Parenthesis; import net.sf.jsqlparser.expression.operators.conditional.AndExpression; import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import org.apache.ibatis.io.Resources; import org.dromara.common.core.domain.dto.RoleDTO; import org.dromara.common.core.domain.model.LoginUser; import org.dromara.common.core.exception.ServiceException; @@ -21,16 +21,26 @@ import org.dromara.common.mybatis.annotation.DataPermission; import org.dromara.common.mybatis.enums.DataScopeType; import org.dromara.common.mybatis.helper.DataPermissionHelper; import org.dromara.common.satoken.utils.LoginHelper; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.expression.BeanFactoryResolver; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.core.type.ClassMetadata; +import org.springframework.core.type.classreading.CachingMetadataReaderFactory; import org.springframework.expression.BeanResolver; import org.springframework.expression.ExpressionParser; import org.springframework.expression.ParserContext; import org.springframework.expression.common.TemplateParserContext; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.util.ClassUtils; import java.lang.reflect.Method; -import java.util.*; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; @@ -58,9 +68,13 @@ public class PlusDataPermissionHandler { */ private final BeanResolver beanResolver = new BeanFactoryResolver(SpringUtils.getBeanFactory()); + public PlusDataPermissionHandler(String mapperPackage) { + scanMapperClasses(mapperPackage); + } + public Expression getSqlSegment(Expression where, String mappedStatementId, boolean isSelect) { - DataColumn[] dataColumns = findAnnotation(mappedStatementId); + DataPermission dataPermission = getDataPermission(mappedStatementId); LoginUser currentUser = DataPermissionHelper.getVariable("user"); if (ObjectUtil.isNull(currentUser)) { currentUser = LoginHelper.getLoginUser(); @@ -70,7 +84,7 @@ public class PlusDataPermissionHandler { if (LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin()) { return where; } - String dataFilterSql = buildDataFilter(dataColumns, isSelect); + String dataFilterSql = buildDataFilter(dataPermission.value(), isSelect); if (StringUtils.isBlank(dataFilterSql)) { return where; } @@ -144,43 +158,64 @@ public class PlusDataPermissionHandler { return ""; } - public DataColumn[] findAnnotation(String mappedStatementId) { - StringBuilder sb = new StringBuilder(mappedStatementId); - int index = sb.lastIndexOf("."); - String clazzName = sb.substring(0, index); - String methodName = sb.substring(index + 1, sb.length()); - Class clazz; + /** + * 通过 mapperPackage 设置的扫描包 扫描缓存有注解的方法与类 + */ + private void scanMapperClasses(String mapperPackage) { + PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); + CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory(); + String[] packagePatternArray = StringUtils.splitPreserveAllTokens(mapperPackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); + String classpath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX; try { - clazz = ClassUtil.loadClass(clazzName); + for (String packagePattern : packagePatternArray) { + String path = ClassUtils.convertClassNameToResourcePath(packagePattern); + Resource[] resources = resolver.getResources(classpath + path + "/*.class"); + for (Resource resource : resources) { + ClassMetadata classMetadata = factory.getMetadataReader(resource).getClassMetadata(); + Class clazz = Resources.classForName(classMetadata.getClassName()); + findAnnotation(clazz); + } + } } catch (Exception e) { - return null; + log.error("初始化数据安全缓存时出错:{}", e.getMessage()); } - List methods = Arrays.stream(ClassUtil.getDeclaredMethods(clazz)) - .filter(method -> method.getName().equals(methodName)).toList(); + } + + private void findAnnotation(Class clazz) { DataPermission dataPermission; // 获取方法注解 - for (Method method : methods) { - dataPermission = dataPermissionCacheMap.get(mappedStatementId); - if (ObjectUtil.isNotNull(dataPermission)) { - return dataPermission.value(); + for (Method method : clazz.getMethods()) { + if (method.isDefault() || method.isVarArgs()) { + continue; } + String mappedStatementId = clazz.getName() + "." + method.getName(); if (AnnotationUtil.hasAnnotation(method, DataPermission.class)) { dataPermission = AnnotationUtil.getAnnotation(method, DataPermission.class); dataPermissionCacheMap.put(mappedStatementId, dataPermission); - return dataPermission.value(); } } - dataPermission = dataPermissionCacheMap.get(clazz.getName()); - if (ObjectUtil.isNotNull(dataPermission)) { - return dataPermission.value(); - } // 获取类注解 if (AnnotationUtil.hasAnnotation(clazz, DataPermission.class)) { dataPermission = AnnotationUtil.getAnnotation(clazz, DataPermission.class); dataPermissionCacheMap.put(clazz.getName(), dataPermission); - return dataPermission.value(); + } + } + + public DataPermission getDataPermission(String mapperId) { + if (dataPermissionCacheMap.containsKey(mapperId)) { + return dataPermissionCacheMap.get(mapperId); + } + String clazzName = mapperId.substring(0, mapperId.lastIndexOf(".")); + if (dataPermissionCacheMap.containsKey(clazzName)) { + return dataPermissionCacheMap.get(clazzName); } return null; } + /** + * 是否无效 + */ + public boolean invalid(String mapperId) { + return getDataPermission(mapperId) == null; + } } diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/interceptor/PlusDataPermissionInterceptor.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/interceptor/PlusDataPermissionInterceptor.java index 0ab0c1139..f287846ce 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/interceptor/PlusDataPermissionInterceptor.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/interceptor/PlusDataPermissionInterceptor.java @@ -1,13 +1,10 @@ package org.dromara.common.mybatis.interceptor; -import cn.hutool.core.collection.ConcurrentHashSet; -import cn.hutool.core.util.ArrayUtil; import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper; import com.baomidou.mybatisplus.core.toolkit.PluginUtils; import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport; import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; -import org.dromara.common.mybatis.annotation.DataColumn; -import org.dromara.common.mybatis.handler.PlusDataPermissionHandler; +import lombok.extern.slf4j.Slf4j; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.statement.delete.Delete; import net.sf.jsqlparser.statement.select.PlainSelect; @@ -22,11 +19,11 @@ import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.SqlCommandType; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; +import org.dromara.common.mybatis.handler.PlusDataPermissionHandler; import java.sql.Connection; import java.sql.SQLException; import java.util.List; -import java.util.Set; /** * 数据权限拦截器 @@ -34,13 +31,14 @@ import java.util.Set; * @author Lion Li * @version 3.5.0 */ +@Slf4j public class PlusDataPermissionInterceptor extends JsqlParserSupport implements InnerInterceptor { - private final PlusDataPermissionHandler dataPermissionHandler = new PlusDataPermissionHandler(); - /** - * 无效注解方法缓存用于快速返回 - */ - private final Set invalidCacheSet = new ConcurrentHashSet<>(); + private final PlusDataPermissionHandler dataPermissionHandler; + + public PlusDataPermissionInterceptor(String mapperPackage) { + this.dataPermissionHandler = new PlusDataPermissionHandler(mapperPackage); + } @Override public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { @@ -49,12 +47,7 @@ public class PlusDataPermissionInterceptor extends JsqlParserSupport implements return; } // 检查是否无效 无数据权限注解 - if (invalidCacheSet.contains(ms.getId())) { - return; - } - DataColumn[] dataColumns = dataPermissionHandler.findAnnotation(ms.getId()); - if (ArrayUtil.isEmpty(dataColumns)) { - invalidCacheSet.add(ms.getId()); + if (dataPermissionHandler.invalid(ms.getId())) { return; } // 解析 sql 分配对应方法 @@ -72,12 +65,7 @@ public class PlusDataPermissionInterceptor extends JsqlParserSupport implements return; } // 检查是否无效 无数据权限注解 - if (invalidCacheSet.contains(ms.getId())) { - return; - } - DataColumn[] dataColumns = dataPermissionHandler.findAnnotation(ms.getId()); - if (ArrayUtil.isEmpty(dataColumns)) { - invalidCacheSet.add(ms.getId()); + if (dataPermissionHandler.invalid(ms.getId())) { return; } PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql(); diff --git a/ruoyi-admin/src/main/resources/spy.properties b/ruoyi-common/ruoyi-common-mybatis/src/main/resources/spy.properties similarity index 80% rename from ruoyi-admin/src/main/resources/spy.properties rename to ruoyi-common/ruoyi-common-mybatis/src/main/resources/spy.properties index abbd8931d..e9d10f3f1 100644 --- a/ruoyi-admin/src/main/resources/spy.properties +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/resources/spy.properties @@ -6,8 +6,6 @@ logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger # 使用日志系统记录 sql #appender=com.p6spy.engine.spy.appender.Slf4JLogger -# 设置 p6spy driver 代理 -#deregisterdrivers=true # 取消JDBC URL前缀 useprefix=true # 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset. @@ -16,12 +14,6 @@ excludecategories=info,debug,result,commit,resultset dateformat=yyyy-MM-dd HH:mm:ss # SQL语句打印时间格式 databaseDialectTimestampFormat=yyyy-MM-dd HH:mm:ss -# 实际驱动可多个 -#driverlist=org.h2.Driver -# 是否开启慢SQL记录 -outagedetection=true -# 慢SQL记录标准 2 秒 -outagedetectioninterval=2 # 是否过滤 Log filter=true # 过滤 Log 时所排除的 sql 关键字,以逗号分隔 diff --git a/ruoyi-common/ruoyi-common-oss/pom.xml b/ruoyi-common/ruoyi-common-oss/pom.xml index 8e7affff4..18d004f57 100644 --- a/ruoyi-common/ruoyi-common-oss/pom.xml +++ b/ruoyi-common/ruoyi-common-oss/pom.xml @@ -26,10 +26,46 @@ ruoyi-common-redis + - com.amazonaws - aws-java-sdk-s3 + software.amazon.awssdk + s3 + + + + software.amazon.awssdk + netty-nio-client + + + + software.amazon.awssdk + aws-crt-client + + + + software.amazon.awssdk + apache-client + + + + software.amazon.awssdk + url-connection-client + + + + + + software.amazon.awssdk.crt + aws-crt + + + + + software.amazon.awssdk + s3-transfer-manager + + diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java b/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java index 53e05c927..eb1656c06 100644 --- a/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java +++ b/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java @@ -2,73 +2,114 @@ package org.dromara.common.oss.core; import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.IdUtil; -import com.amazonaws.ClientConfiguration; -import com.amazonaws.HttpMethod; -import com.amazonaws.Protocol; -import com.amazonaws.auth.AWSCredentials; -import com.amazonaws.auth.AWSCredentialsProvider; -import com.amazonaws.auth.AWSStaticCredentialsProvider; -import com.amazonaws.auth.BasicAWSCredentials; -import com.amazonaws.client.builder.AwsClientBuilder; -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.AmazonS3Client; -import com.amazonaws.services.s3.AmazonS3ClientBuilder; -import com.amazonaws.services.s3.model.*; +import org.dromara.common.core.constant.Constants; import org.dromara.common.core.utils.DateUtils; import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.file.FileUtils; import org.dromara.common.oss.constant.OssConstant; import org.dromara.common.oss.entity.UploadResult; import org.dromara.common.oss.enumd.AccessPolicyType; import org.dromara.common.oss.enumd.PolicyType; import org.dromara.common.oss.exception.OssException; import org.dromara.common.oss.properties.OssProperties; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.core.async.AsyncRequestBody; +import software.amazon.awssdk.core.async.BlockingInputStreamAsyncRequestBody; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3AsyncClient; +import software.amazon.awssdk.services.s3.S3Configuration; +import software.amazon.awssdk.services.s3.model.NoSuchBucketException; +import software.amazon.awssdk.services.s3.model.S3Exception; +import software.amazon.awssdk.services.s3.presigner.S3Presigner; +import software.amazon.awssdk.transfer.s3.S3TransferManager; +import software.amazon.awssdk.transfer.s3.model.*; +import software.amazon.awssdk.transfer.s3.progress.LoggingTransferListener; import java.io.ByteArrayInputStream; import java.io.File; +import java.io.IOException; import java.io.InputStream; +import java.net.URI; import java.net.URL; -import java.util.Date; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Duration; /** * S3 存储协议 所有兼容S3协议的云厂商均支持 * 阿里云 腾讯云 七牛云 minio * - * @author Lion Li + * @author AprilWind */ public class OssClient { + /** + * 服务商 + */ private final String configKey; + /** + * 配置属性 + */ private final OssProperties properties; - private final AmazonS3 client; + /** + * Amazon S3 异步客户端 + */ + private final S3AsyncClient client; + /** + * 用于管理 S3 数据传输的高级工具 + */ + private final S3TransferManager transferManager; + + /** + * AWS S3 预签名 URL 的生成器 + */ + private final S3Presigner presigner; + + /** + * 构造方法 + * + * @param configKey 配置键 + * @param ossProperties Oss配置属性 + */ public OssClient(String configKey, OssProperties ossProperties) { this.configKey = configKey; this.properties = ossProperties; try { - AwsClientBuilder.EndpointConfiguration endpointConfig = - new AwsClientBuilder.EndpointConfiguration(properties.getEndpoint(), properties.getRegion()); + // 创建 AWS 认证信息 + StaticCredentialsProvider credentialsProvider = StaticCredentialsProvider.create( + AwsBasicCredentials.create(properties.getAccessKey(), properties.getSecretKey())); - AWSCredentials credentials = new BasicAWSCredentials(properties.getAccessKey(), properties.getSecretKey()); - AWSCredentialsProvider credentialsProvider = new AWSStaticCredentialsProvider(credentials); - ClientConfiguration clientConfig = new ClientConfiguration(); - if (OssConstant.IS_HTTPS.equals(properties.getIsHttps())) { - clientConfig.setProtocol(Protocol.HTTPS); - } else { - clientConfig.setProtocol(Protocol.HTTP); - } - AmazonS3ClientBuilder build = AmazonS3Client.builder() - .withEndpointConfiguration(endpointConfig) - .withClientConfiguration(clientConfig) - .withCredentials(credentialsProvider) - .disableChunkedEncoding(); - if (!StringUtils.containsAny(properties.getEndpoint(), OssConstant.CLOUD_SERVICE)) { + //创建AWS基于 CRT 的 S3 客户端 + this.client = S3AsyncClient.crtBuilder() + .credentialsProvider(credentialsProvider) + .endpointOverride(URI.create(getEndpoint())) + .region(of()) + .targetThroughputInGbps(20.0) + .minimumPartSizeInBytes(10 * 1025 * 1024L) + .checksumValidationEnabled(false) + .build(); + + //AWS基于 CRT 的 S3 AsyncClient 实例用作 S3 传输管理器的底层客户端 + this.transferManager = S3TransferManager.builder().s3Client(this.client).build(); + + // 检查是否连接到 MinIO,MinIO 使用 HTTPS 限制使用域名访问,需要启用路径样式访问 + S3Configuration config = S3Configuration.builder().chunkedEncodingEnabled(false) // minio 使用https限制使用域名访问 需要此配置 站点填域名 - build.enablePathStyleAccess(); - } - this.client = build.build(); + .pathStyleAccessEnabled(!StringUtils.containsAny(properties.getEndpoint(), OssConstant.CLOUD_SERVICE)).build(); + // 创建 预签名 URL 的生成器 实例,用于生成 S3 预签名 URL + this.presigner = S3Presigner.builder() + .region(of()) + .credentialsProvider(credentialsProvider) + .endpointOverride(URI.create(getDomain())) + .serviceConfiguration(config) + .build(); + + // 创建存储桶 createBucket(); } catch (Exception e) { if (e instanceof OssException) { @@ -78,126 +119,158 @@ public class OssClient { } } + /** + * 同步创建存储桶 + * 如果存储桶不存在,会进行创建;如果存储桶存在,不执行任何操作 + * + * @throws OssException 当创建存储桶时发生异常时抛出 + */ public void createBucket() { + String bucketName = properties.getBucketName(); try { - String bucketName = properties.getBucketName(); - if (client.doesBucketExistV2(bucketName)) { - return; + // 尝试获取存储桶的信息 + client.headBucket( + x -> x.bucket(bucketName) + .build()) + .join(); + } catch (Exception ex) { + if (ex.getCause() instanceof NoSuchBucketException) { + try { + // 存储桶不存在,尝试创建存储桶 + client.createBucket( + x -> x.bucket(bucketName)) + .join(); + + // 设置存储桶的访问策略(Bucket Policy) + client.putBucketPolicy( + x -> x.bucket(bucketName) + .policy(getPolicy(bucketName, getAccessPolicy().getPolicyType()))) + .join(); + } catch (S3Exception e) { + // 存储桶创建或策略设置失败 + throw new OssException("创建Bucket失败, 请核对配置信息:[" + e.getMessage() + "]"); + } + } else { + throw new OssException("判断Bucket是否存在失败,请核对配置信息:[" + ex.getMessage() + "]"); } - CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName); - AccessPolicyType accessPolicy = getAccessPolicy(); - createBucketRequest.setCannedAcl(accessPolicy.getAcl()); - client.createBucket(createBucketRequest); - client.setBucketPolicy(bucketName, getPolicy(bucketName, accessPolicy.getPolicyType())); - } catch (Exception e) { - throw new OssException("创建Bucket失败, 请核对配置信息:[" + e.getMessage() + "]"); } } - public UploadResult upload(byte[] data, String path, String contentType) { - return upload(new ByteArrayInputStream(data), path, contentType); + /** + * 上传文件到 Amazon S3,并返回上传结果 + * + * @param filePath 本地文件路径 + * @param key 在 Amazon S3 中的对象键 + * @param md5Digest 本地文件的 MD5 哈希值(可选) + * @return UploadResult 包含上传后的文件信息 + * @throws OssException 如果上传失败,抛出自定义异常 + */ + public UploadResult upload(Path filePath, String key, String md5Digest) { + try { + // 构建上传请求对象 + FileUpload fileUpload = transferManager.uploadFile( + x -> x.putObjectRequest( + y -> y.bucket(properties.getBucketName()) + .key(key) + .contentMD5(StringUtils.isNotEmpty(md5Digest) ? md5Digest : null) + .build()) + .addTransferListener(LoggingTransferListener.create()) + .source(filePath).build()); + + // 等待上传完成并获取上传结果 + CompletedFileUpload uploadResult = fileUpload.completionFuture().join(); + String eTag = uploadResult.response().eTag(); + + // 提取上传结果中的 ETag,并构建一个自定义的 UploadResult 对象 + return UploadResult.builder().url(getUrl() + StringUtils.SLASH + key).filename(key).eTag(eTag).build(); + } catch (Exception e) { + // 捕获异常并抛出自定义异常 + throw new OssException("上传文件失败,请检查配置信息:[" + e.getMessage() + "]"); + } finally { + // 无论上传是否成功,最终都会删除临时文件 + FileUtils.del(filePath); + } } - public UploadResult upload(InputStream inputStream, String path, String contentType) { + /** + * 上传 InputStream 到 Amazon S3 + * + * @param inputStream 要上传的输入流 + * @param key 在 Amazon S3 中的对象键 + * @param length 输入流的长度 + * @return UploadResult 包含上传后的文件信息 + * @throws OssException 如果上传失败,抛出自定义异常 + */ + public UploadResult upload(InputStream inputStream, String key, Long length) { + // 如果输入流不是 ByteArrayInputStream,则将其读取为字节数组再创建 ByteArrayInputStream if (!(inputStream instanceof ByteArrayInputStream)) { inputStream = new ByteArrayInputStream(IoUtil.readBytes(inputStream)); } try { - ObjectMetadata metadata = new ObjectMetadata(); - metadata.setContentType(contentType); - metadata.setContentLength(inputStream.available()); - PutObjectRequest putObjectRequest = new PutObjectRequest(properties.getBucketName(), path, inputStream, metadata); - // 设置上传对象的 Acl 为公共读 - putObjectRequest.setCannedAcl(getAccessPolicy().getAcl()); - client.putObject(putObjectRequest); + // 创建异步请求体(length如果为空会报错) + BlockingInputStreamAsyncRequestBody body = AsyncRequestBody.forBlockingInputStream(length); + + // 使用 transferManager 进行上传 + Upload upload = transferManager.upload( + x -> x.requestBody(body) + .putObjectRequest( + y -> y.bucket(properties.getBucketName()) + .key(key) + .build()) + .build()); + + // 将输入流写入请求体 + body.writeInputStream(inputStream); + + // 等待文件上传操作完成 + CompletedUpload uploadResult = upload.completionFuture().join(); + String eTag = uploadResult.response().eTag(); + + // 提取上传结果中的 ETag,并构建一个自定义的 UploadResult 对象 + return UploadResult.builder().url(getUrl() + StringUtils.SLASH + key).filename(key).eTag(eTag).build(); } catch (Exception e) { throw new OssException("上传文件失败,请检查配置信息:[" + e.getMessage() + "]"); } - return UploadResult.builder().url(getUrl() + "/" + path).filename(path).build(); - } - - public UploadResult upload(File file, String path) { - try { - PutObjectRequest putObjectRequest = new PutObjectRequest(properties.getBucketName(), path, file); - // 设置上传对象的 Acl 为公共读 - putObjectRequest.setCannedAcl(getAccessPolicy().getAcl()); - client.putObject(putObjectRequest); - } catch (Exception e) { - throw new OssException("上传文件失败,请检查配置信息:[" + e.getMessage() + "]"); - } - return UploadResult.builder().url(getUrl() + "/" + path).filename(path).build(); - } - - public void delete(String path) { - path = path.replace(getUrl() + "/", ""); - try { - client.deleteObject(properties.getBucketName(), path); - } catch (Exception e) { - throw new OssException("删除文件失败,请检查配置信息:[" + e.getMessage() + "]"); - } - } - - public UploadResult uploadSuffix(byte[] data, String suffix, String contentType) { - return upload(data, getPath(properties.getPrefix(), suffix), contentType); - } - - public UploadResult uploadSuffix(InputStream inputStream, String suffix, String contentType) { - return upload(inputStream, getPath(properties.getPrefix(), suffix), contentType); - } - - public UploadResult uploadSuffix(File file, String suffix) { - return upload(file, getPath(properties.getPrefix(), suffix)); } /** - * 获取文件元数据 + * 下载文件从 Amazon S3 到临时目录 * - * @param path 完整文件路径 + * @param path 文件在 Amazon S3 中的对象键 + * @return 下载后的文件在本地的临时路径 + * @throws OssException 如果下载失败,抛出自定义异常 */ - public ObjectMetadata getObjectMetadata(String path) { - path = path.replace(getUrl() + "/", ""); - S3Object object = client.getObject(properties.getBucketName(), path); - return object.getObjectMetadata(); + public Path fileDownload(String path) { + // 构建临时文件 + Path tempFilePath = FileUtils.createTempFile().toPath(); + // 使用 S3TransferManager 下载文件 + FileDownload downloadFile = transferManager.downloadFile( + x -> x.getObjectRequest( + y -> y.bucket(properties.getBucketName()) + .key(removeBaseUrl(path)) + .build()) + .addTransferListener(LoggingTransferListener.create()) + .destination(tempFilePath) + .build()); + // 等待文件下载操作完成 + downloadFile.completionFuture().join(); + return tempFilePath; } - public InputStream getObjectContent(String path) { - path = path.replace(getUrl() + "/", ""); - S3Object object = client.getObject(properties.getBucketName(), path); - return object.getObjectContent(); - } - - public String getUrl() { - String domain = properties.getDomain(); - String endpoint = properties.getEndpoint(); - String header = OssConstant.IS_HTTPS.equals(properties.getIsHttps()) ? "https://" : "http://"; - // 云服务商直接返回 - if (StringUtils.containsAny(endpoint, OssConstant.CLOUD_SERVICE)) { - if (StringUtils.isNotBlank(domain)) { - return header + domain; - } - return header + properties.getBucketName() + "." + endpoint; + /** + * 删除云存储服务中指定路径下文件 + * + * @param path 指定路径 + */ + public void delete(String path) { + try { + client.deleteObject( + x -> x.bucket(properties.getBucketName()) + .key(removeBaseUrl(path)) + .build()); + } catch (Exception e) { + throw new OssException("删除文件失败,请检查配置信息:[" + e.getMessage() + "]"); } - // minio 单独处理 - if (StringUtils.isNotBlank(domain)) { - return header + domain + "/" + properties.getBucketName(); - } - return header + endpoint + "/" + properties.getBucketName(); - } - - public String getPath(String prefix, String suffix) { - // 生成uuid - String uuid = IdUtil.fastSimpleUUID(); - // 文件路径 - String path = DateUtils.datePath() + "/" + uuid; - if (StringUtils.isNotBlank(prefix)) { - path = prefix + "/" + path; - } - return path + suffix; - } - - - public String getConfigKey() { - return configKey; } /** @@ -207,14 +280,189 @@ public class OssClient { * @param second 授权时间 */ public String getPrivateUrl(String objectKey, Integer second) { - GeneratePresignedUrlRequest generatePresignedUrlRequest = - new GeneratePresignedUrlRequest(properties.getBucketName(), objectKey) - .withMethod(HttpMethod.GET) - .withExpiration(new Date(System.currentTimeMillis() + 1000L * second)); - URL url = client.generatePresignedUrl(generatePresignedUrlRequest); + // 使用 AWS S3 预签名 URL 的生成器 获取对象的预签名 URL + URL url = presigner.presignGetObject( + x -> x.signatureDuration(Duration.ofSeconds(second)) + .getObjectRequest( + y -> y.bucket(properties.getBucketName()) + .key(objectKey) + .build()) + .build()) + .url(); return url.toString(); } + /** + * 上传 byte[] 数据到 Amazon S3,使用指定的后缀构造对象键。 + * + * @param data 要上传的 byte[] 数据 + * @param suffix 对象键的后缀 + * @return UploadResult 包含上传后的文件信息 + * @throws OssException 如果上传失败,抛出自定义异常 + */ + public UploadResult uploadSuffix(byte[] data, String suffix) { + return upload(new ByteArrayInputStream(data), getPath(properties.getPrefix(), suffix), Long.valueOf(data.length)); + } + + /** + * 上传 InputStream 到 Amazon S3,使用指定的后缀构造对象键。 + * + * @param inputStream 要上传的输入流 + * @param suffix 对象键的后缀 + * @param length 输入流的长度 + * @return UploadResult 包含上传后的文件信息 + * @throws OssException 如果上传失败,抛出自定义异常 + */ + public UploadResult uploadSuffix(InputStream inputStream, String suffix, Long length) { + return upload(inputStream, getPath(properties.getPrefix(), suffix), length); + } + + /** + * 上传文件到 Amazon S3,使用指定的后缀构造对象键 + * + * @param file 要上传的文件 + * @param suffix 对象键的后缀 + * @return UploadResult 包含上传后的文件信息 + * @throws OssException 如果上传失败,抛出自定义异常 + */ + public UploadResult uploadSuffix(File file, String suffix) { + return upload(file.toPath(), getPath(properties.getPrefix(), suffix), null); + } + + /** + * 获取文件输入流 + * + * @param path 完整文件路径 + * @return 输入流 + */ + public InputStream getObjectContent(String path) throws IOException { + // 下载文件到临时目录 + Path tempFilePath = fileDownload(path); + // 创建输入流 + InputStream inputStream = Files.newInputStream(tempFilePath); + // 删除临时文件 + FileUtils.del(tempFilePath); + // 返回对象内容的输入流 + return inputStream; + } + + /** + * 获取 S3 客户端的终端点 URL + * + * @return 终端点 URL + */ + public String getEndpoint() { + // 根据配置文件中的是否使用 HTTPS,设置协议头部 + String header = getIsHttps(); + // 拼接协议头部和终端点,得到完整的终端点 URL + return header + properties.getEndpoint(); + } + + /** + * 获取 S3 客户端的终端点 URL(自定义域名) + * + * @return 终端点 URL + */ + public String getDomain() { + // 从配置中获取域名、终端点、是否使用 HTTPS 等信息 + String domain = properties.getDomain(); + String endpoint = properties.getEndpoint(); + String header = getIsHttps(); + + // 如果是云服务商,直接返回域名或终端点 + if (StringUtils.containsAny(endpoint, OssConstant.CLOUD_SERVICE)) { + return StringUtils.isNotEmpty(domain) ? header + domain : header + endpoint; + } + + // 如果是 MinIO,处理域名并返回 + if (StringUtils.isNotEmpty(domain)) { + return domain.startsWith(Constants.HTTPS) || domain.startsWith(Constants.HTTP) ? domain : header + domain; + } + + // 返回终端点 + return header + endpoint; + } + + /** + * 根据传入的 region 参数返回相应的 AWS 区域 + * 如果 region 参数非空,使用 Region.of 方法创建并返回对应的 AWS 区域对象 + * 如果 region 参数为空,返回一个默认的 AWS 区域(例如,us-east-1),作为广泛支持的区域 + * + * @return 对应的 AWS 区域对象,或者默认的广泛支持的区域(us-east-1) + */ + public Region of() { + //AWS 区域字符串 + String region = properties.getRegion(); + // 如果 region 参数非空,使用 Region.of 方法创建对应的 AWS 区域对象,否则返回默认区域 + return StringUtils.isNotEmpty(region) ? Region.of(region) : Region.US_EAST_1; + } + + /** + * 获取云存储服务的URL + * + * @return 文件路径 + */ + public String getUrl() { + String domain = properties.getDomain(); + String endpoint = properties.getEndpoint(); + String header = getIsHttps(); + // 云服务商直接返回 + if (StringUtils.containsAny(endpoint, OssConstant.CLOUD_SERVICE)) { + return header + (StringUtils.isNotEmpty(domain) ? domain : properties.getBucketName() + "." + endpoint); + } + // MinIO 单独处理 + if (StringUtils.isNotEmpty(domain)) { + // 如果 domain 以 "https://" 或 "http://" 开头 + return (domain.startsWith(Constants.HTTPS) || domain.startsWith(Constants.HTTP)) ? + domain + StringUtils.SLASH + properties.getBucketName() : header + domain + StringUtils.SLASH + properties.getBucketName(); + } + return header + endpoint + StringUtils.SLASH + properties.getBucketName(); + } + + /** + * 生成一个符合特定规则的、唯一的文件路径。通过使用日期、UUID、前缀和后缀等元素的组合,确保了文件路径的独一无二性 + * + * @param prefix 前缀 + * @param suffix 后缀 + * @return 文件路径 + */ + public String getPath(String prefix, String suffix) { + // 生成uuid + String uuid = IdUtil.fastSimpleUUID(); + // 生成日期路径 + String datePath = DateUtils.datePath(); + // 拼接路径 + String path = StringUtils.isNotEmpty(prefix) ? + prefix + StringUtils.SLASH + datePath + StringUtils.SLASH + uuid : datePath + StringUtils.SLASH + uuid; + return path + suffix; + } + + /** + * 移除路径中的基础URL部分,得到相对路径 + * + * @param path 完整的路径,包括基础URL和相对路径 + * @return 去除基础URL后的相对路径 + */ + public String removeBaseUrl(String path) { + return path.replace(getUrl() + StringUtils.SLASH, ""); + } + + /** + * 服务商 + */ + public String getConfigKey() { + return configKey; + } + + /** + * 获取是否使用 HTTPS 的配置,并返回相应的协议头部。 + * + * @return 协议头部,根据是否使用 HTTPS 返回 "https://" 或 "http://" + */ + public String getIsHttps() { + return OssConstant.IS_HTTPS.equals(properties.getIsHttps()) ? Constants.HTTPS : Constants.HTTP; + } + /** * 检查配置是否相同 */ @@ -231,32 +479,77 @@ public class OssClient { return AccessPolicyType.getByType(properties.getAccessPolicy()); } + /** + * 生成 AWS S3 存储桶访问策略 + * + * @param bucketName 存储桶 + * @param policyType 桶策略类型 + * @return 符合 AWS S3 存储桶访问策略格式的字符串 + */ private static String getPolicy(String bucketName, PolicyType policyType) { - StringBuilder builder = new StringBuilder(); - builder.append("{\n\"Statement\": [\n{\n\"Action\": [\n"); - builder.append(switch (policyType) { - case WRITE -> "\"s3:GetBucketLocation\",\n\"s3:ListBucketMultipartUploads\"\n"; - case READ_WRITE -> "\"s3:GetBucketLocation\",\n\"s3:ListBucket\",\n\"s3:ListBucketMultipartUploads\"\n"; - default -> "\"s3:GetBucketLocation\"\n"; - }); - builder.append("],\n\"Effect\": \"Allow\",\n\"Principal\": \"*\",\n\"Resource\": \"arn:aws:s3:::"); - builder.append(bucketName); - builder.append("\"\n},\n"); - if (policyType == PolicyType.READ) { - builder.append("{\n\"Action\": [\n\"s3:ListBucket\"\n],\n\"Effect\": \"Deny\",\n\"Principal\": \"*\",\n\"Resource\": \"arn:aws:s3:::"); - builder.append(bucketName); - builder.append("\"\n},\n"); - } - builder.append("{\n\"Action\": "); - builder.append(switch (policyType) { - case WRITE -> "[\n\"s3:AbortMultipartUpload\",\n\"s3:DeleteObject\",\n\"s3:ListMultipartUploadParts\",\n\"s3:PutObject\"\n],\n"; - case READ_WRITE -> "[\n\"s3:AbortMultipartUpload\",\n\"s3:DeleteObject\",\n\"s3:GetObject\",\n\"s3:ListMultipartUploadParts\",\n\"s3:PutObject\"\n],\n"; - default -> "\"s3:GetObject\",\n"; - }); - builder.append("\"Effect\": \"Allow\",\n\"Principal\": \"*\",\n\"Resource\": \"arn:aws:s3:::"); - builder.append(bucketName); - builder.append("/*\"\n}\n],\n\"Version\": \"2012-10-17\"\n}\n"); - return builder.toString(); + String policy = switch (policyType) { + case WRITE -> """ + { + "Version": "2012-10-17", + "Statement": [] + } + """; + case READ_WRITE -> """ + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": "*", + "Action": [ + "s3:GetBucketLocation", + "s3:ListBucket", + "s3:ListBucketMultipartUploads" + ], + "Resource": "arn:aws:s3:::bucketName" + }, + { + "Effect": "Allow", + "Principal": "*", + "Action": [ + "s3:AbortMultipartUpload", + "s3:DeleteObject", + "s3:GetObject", + "s3:ListMultipartUploadParts", + "s3:PutObject" + ], + "Resource": "arn:aws:s3:::bucketName/*" + } + ] + } + """; + case READ -> """ + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": "*", + "Action": ["s3:GetBucketLocation"], + "Resource": "arn:aws:s3:::bucketName" + }, + { + "Effect": "Deny", + "Principal": "*", + "Action": ["s3:ListBucket"], + "Resource": "arn:aws:s3:::bucketName" + }, + { + "Effect": "Allow", + "Principal": "*", + "Action": "s3:GetObject", + "Resource": "arn:aws:s3:::bucketName/*" + } + ] + } + """; + }; + return policy.replaceAll("bucketName", bucketName); } } diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/entity/UploadResult.java b/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/entity/UploadResult.java index a6f57e5ad..81a18e62a 100644 --- a/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/entity/UploadResult.java +++ b/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/entity/UploadResult.java @@ -21,4 +21,10 @@ public class UploadResult { * 文件名 */ private String filename; + + /** + * 已上传对象的实体标记(用来校验文件) + */ + private String eTag; + } diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/enumd/AccessPolicyType.java b/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/enumd/AccessPolicyType.java index 9074d72de..6d39133d5 100644 --- a/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/enumd/AccessPolicyType.java +++ b/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/enumd/AccessPolicyType.java @@ -1,8 +1,9 @@ package org.dromara.common.oss.enumd; -import com.amazonaws.services.s3.model.CannedAccessControlList; import lombok.AllArgsConstructor; import lombok.Getter; +import software.amazon.awssdk.services.s3.model.BucketCannedACL; +import software.amazon.awssdk.services.s3.model.ObjectCannedACL; /** * 桶访问策略配置 @@ -16,27 +17,32 @@ public enum AccessPolicyType { /** * private */ - PRIVATE("0", CannedAccessControlList.Private, PolicyType.WRITE), + PRIVATE("0", BucketCannedACL.PRIVATE, ObjectCannedACL.PRIVATE, PolicyType.WRITE), /** * public */ - PUBLIC("1", CannedAccessControlList.PublicRead, PolicyType.READ), + PUBLIC("1", BucketCannedACL.PUBLIC_READ_WRITE, ObjectCannedACL.PUBLIC_READ_WRITE, PolicyType.READ_WRITE), /** * custom */ - CUSTOM("2",CannedAccessControlList.PublicRead, PolicyType.READ); + CUSTOM("2", BucketCannedACL.PUBLIC_READ, ObjectCannedACL.PUBLIC_READ, PolicyType.READ); /** - * 桶 权限类型 + * 桶 权限类型(数据库值) */ private final String type; + /** + * 桶 权限类型 + */ + private final BucketCannedACL bucketCannedACL; + /** * 文件对象 权限类型 */ - private final CannedAccessControlList acl; + private final ObjectCannedACL objectCannedACL; /** * 桶策略类型 diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/factory/OssFactory.java b/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/factory/OssFactory.java index 763b090e3..d70270a15 100644 --- a/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/factory/OssFactory.java +++ b/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/factory/OssFactory.java @@ -1,5 +1,6 @@ package org.dromara.common.oss.factory; +import lombok.extern.slf4j.Slf4j; import org.dromara.common.core.constant.CacheNames; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.json.utils.JsonUtils; @@ -9,10 +10,10 @@ import org.dromara.common.oss.exception.OssException; import org.dromara.common.oss.properties.OssProperties; import org.dromara.common.redis.utils.CacheUtils; import org.dromara.common.redis.utils.RedisUtils; -import lombok.extern.slf4j.Slf4j; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReentrantLock; /** * 文件上传Factory @@ -23,6 +24,7 @@ import java.util.concurrent.ConcurrentHashMap; public class OssFactory { private static final Map CLIENT_CACHE = new ConcurrentHashMap<>(); + private static final ReentrantLock LOCK = new ReentrantLock(); /** * 获取默认实例 @@ -39,7 +41,7 @@ public class OssFactory { /** * 根据类型获取实例 */ - public static synchronized OssClient instance(String configKey) { + public static OssClient instance(String configKey) { String json = CacheUtils.get(CacheNames.SYS_OSS_CONFIG, configKey); if (json == null) { throw new OssException("系统异常, '" + configKey + "'配置信息不存在!"); @@ -48,16 +50,19 @@ public class OssFactory { // 使用租户标识避免多个租户相同key实例覆盖 String key = properties.getTenantId() + ":" + configKey; OssClient client = CLIENT_CACHE.get(key); - if (client == null) { - CLIENT_CACHE.put(key, new OssClient(configKey, properties)); - log.info("创建OSS实例 key => {}", configKey); - return CLIENT_CACHE.get(key); - } - // 配置不相同则重新构建 - if (!client.checkPropertiesSame(properties)) { - CLIENT_CACHE.put(key, new OssClient(configKey, properties)); - log.info("重载OSS实例 key => {}", configKey); - return CLIENT_CACHE.get(key); + // 客户端不存在或配置不相同则重新构建 + if (client == null || !client.checkPropertiesSame(properties)) { + LOCK.lock(); + try { + client = CLIENT_CACHE.get(key); + if (client == null || !client.checkPropertiesSame(properties)) { + CLIENT_CACHE.put(key, new OssClient(configKey, properties)); + log.info("创建OSS实例 key => {}", configKey); + return CLIENT_CACHE.get(key); + } + } finally { + LOCK.unlock(); + } } return client; } diff --git a/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java b/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java index 8f3a5cafb..02735b073 100644 --- a/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java +++ b/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java @@ -1,29 +1,29 @@ package org.dromara.common.ratelimiter.aspectj; -import cn.hutool.core.util.ArrayUtil; -import org.dromara.common.core.constant.GlobalConstants; -import org.dromara.common.core.exception.ServiceException; -import org.dromara.common.core.utils.MessageUtils; -import org.dromara.common.core.utils.ServletUtils; -import org.dromara.common.core.utils.StringUtils; -import org.dromara.common.ratelimiter.annotation.RateLimiter; -import org.dromara.common.ratelimiter.enums.LimitType; -import org.dromara.common.redis.utils.RedisUtils; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.reflect.MethodSignature; +import org.dromara.common.core.constant.GlobalConstants; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.MessageUtils; +import org.dromara.common.core.utils.ServletUtils; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.ratelimiter.annotation.RateLimiter; +import org.dromara.common.ratelimiter.enums.LimitType; +import org.dromara.common.redis.utils.RedisUtils; import org.redisson.api.RateType; +import org.springframework.context.expression.BeanFactoryResolver; +import org.springframework.context.expression.MethodBasedEvaluationContext; import org.springframework.core.DefaultParameterNameDiscoverer; import org.springframework.core.ParameterNameDiscoverer; -import org.springframework.expression.EvaluationContext; import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; import org.springframework.expression.ParserContext; import org.springframework.expression.common.TemplateParserContext; import org.springframework.expression.spel.standard.SpelExpressionParser; -import org.springframework.expression.spel.support.StandardEvaluationContext; import java.lang.reflect.Method; @@ -44,21 +44,18 @@ public class RateLimiterAspect { * 定义spel解析模版 */ private final ParserContext parserContext = new TemplateParserContext(); - /** - * 定义spel上下文对象进行解析 - */ - private final EvaluationContext context = new StandardEvaluationContext(); /** * 方法参数解析器 */ private final ParameterNameDiscoverer pnd = new DefaultParameterNameDiscoverer(); + @Before("@annotation(rateLimiter)") - public void doBefore(JoinPoint point, RateLimiter rateLimiter) throws Throwable { + public void doBefore(JoinPoint point, RateLimiter rateLimiter) { int time = rateLimiter.time(); int count = rateLimiter.count(); - String combineKey = getCombineKey(rateLimiter, point); try { + String combineKey = getCombineKey(rateLimiter, point); RateType rateType = RateType.OVERALL; if (rateLimiter.limitType() == LimitType.CLUSTER) { rateType = RateType.PER_CLIENT; @@ -76,42 +73,29 @@ public class RateLimiterAspect { if (e instanceof ServiceException) { throw e; } else { - throw new RuntimeException("服务器限流异常,请稍候再试"); + throw new RuntimeException("服务器限流异常,请稍候再试", e); } } } - public String getCombineKey(RateLimiter rateLimiter, JoinPoint point) { + private String getCombineKey(RateLimiter rateLimiter, JoinPoint point) { String key = rateLimiter.key(); - // 获取方法(通过方法签名来获取) - MethodSignature signature = (MethodSignature) point.getSignature(); - Method method = signature.getMethod(); - Class targetClass = method.getDeclaringClass(); - // 判断是否是spel格式 - if (StringUtils.containsAny(key, "#")) { - // 获取参数值 + if (StringUtils.isNotBlank(key)) { + MethodSignature signature = (MethodSignature) point.getSignature(); + Method targetMethod = signature.getMethod(); Object[] args = point.getArgs(); - // 获取方法上参数的名称 - String[] parameterNames = pnd.getParameterNames(method); - if (ArrayUtil.isEmpty(parameterNames)) { - throw new ServiceException("限流key解析异常!请联系管理员!"); - } - for (int i = 0; i < parameterNames.length; i++) { - context.setVariable(parameterNames[i], args[i]); - } - // 解析返回给key - try { - Expression expression; - if (StringUtils.startsWith(key, parserContext.getExpressionPrefix()) - && StringUtils.endsWith(key, parserContext.getExpressionSuffix())) { - expression = parser.parseExpression(key, parserContext); - } else { - expression = parser.parseExpression(key); - } - key = expression.getValue(context, String.class) + ":"; - } catch (Exception e) { - throw new ServiceException("限流key解析异常!请联系管理员!"); + //noinspection DataFlowIssue + MethodBasedEvaluationContext context = + new MethodBasedEvaluationContext(null, targetMethod, args, pnd); + context.setBeanResolver(new BeanFactoryResolver(SpringUtils.getBeanFactory())); + Expression expression; + if (StringUtils.startsWith(key, parserContext.getExpressionPrefix()) + && StringUtils.endsWith(key, parserContext.getExpressionSuffix())) { + expression = parser.parseExpression(key, parserContext); + } else { + expression = parser.parseExpression(key); } + key = expression.getValue(context, String.class); } StringBuilder stringBuffer = new StringBuilder(GlobalConstants.RATE_LIMIT_KEY); stringBuffer.append(ServletUtils.getRequest().getRequestURI()).append(":"); diff --git a/ruoyi-common/ruoyi-common-ratelimiter/src/main/resources/spel-extension.json b/ruoyi-common/ruoyi-common-ratelimiter/src/main/resources/spel-extension.json new file mode 100644 index 000000000..b16432b29 --- /dev/null +++ b/ruoyi-common/ruoyi-common-ratelimiter/src/main/resources/spel-extension.json @@ -0,0 +1,7 @@ +{ + "org.dromara.common.ratelimiter.annotation.RateLimiter@key": { + "method": { + "parameters": true + } + } +} diff --git a/ruoyi-common/ruoyi-common-redis/pom.xml b/ruoyi-common/ruoyi-common-redis/pom.xml index 5e5c277f3..140866575 100644 --- a/ruoyi-common/ruoyi-common-redis/pom.xml +++ b/ruoyi-common/ruoyi-common-redis/pom.xml @@ -32,6 +32,11 @@ com.baomidou lock4j-redisson-spring-boot-starter + + + com.github.ben-manes.caffeine + caffeine + diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/CacheConfig.java b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/CacheConfig.java new file mode 100644 index 000000000..d57ba4e65 --- /dev/null +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/CacheConfig.java @@ -0,0 +1,45 @@ +package org.dromara.common.redis.config; + +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import org.dromara.common.redis.manager.PlusSpringCacheManager; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Bean; + +import java.util.concurrent.TimeUnit; + +/** + * 缓存配置 + * + * @author Lion Li + */ +@AutoConfiguration +@EnableCaching +public class CacheConfig { + + /** + * caffeine 本地缓存处理器 + */ + @Bean + public Cache caffeine() { + return Caffeine.newBuilder() + // 设置最后一次写入或访问后经过固定时间过期 + .expireAfterWrite(30, TimeUnit.SECONDS) + // 初始的缓存空间大小 + .initialCapacity(100) + // 缓存的最大条数 + .maximumSize(1000) + .build(); + } + + /** + * 自定义缓存管理器 整合spring-cache + */ + @Bean + public CacheManager cacheManager() { + return new PlusSpringCacheManager(); + } + +} diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/RedisConfig.java b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/RedisConfig.java index 7999f2b34..f4328f4d4 100644 --- a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/RedisConfig.java +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/RedisConfig.java @@ -6,9 +6,9 @@ import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.utils.SpringUtils; import org.dromara.common.redis.config.properties.RedissonProperties; import org.dromara.common.redis.handler.KeyPrefixHandler; -import org.dromara.common.redis.manager.PlusSpringCacheManager; import org.redisson.client.codec.StringCodec; import org.redisson.codec.CompositeCodec; import org.redisson.codec.TypedJsonJacksonCodec; @@ -16,9 +16,8 @@ import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cache.CacheManager; -import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; +import org.springframework.core.task.VirtualThreadTaskExecutor; /** * redis配置 @@ -27,7 +26,6 @@ import org.springframework.context.annotation.Bean; */ @Slf4j @AutoConfiguration -@EnableCaching @EnableConfigurationProperties(RedissonProperties.class) public class RedisConfig { @@ -52,6 +50,9 @@ public class RedisConfig { // 缓存 Lua 脚本 减少网络传输(redisson 大部分的功能都是基于 Lua 脚本实现) .setUseScriptCache(true) .setCodec(codec); + if (SpringUtils.isVirtual()) { + config.setNettyExecutor(new VirtualThreadTaskExecutor("redisson-")); + } RedissonProperties.SingleServerConfig singleServerConfig = redissonProperties.getSingleServerConfig(); if (ObjectUtil.isNotNull(singleServerConfig)) { // 使用单机模式 @@ -86,14 +87,6 @@ public class RedisConfig { }; } - /** - * 自定义缓存管理器 整合spring-cache - */ - @Bean - public CacheManager cacheManager() { - return new PlusSpringCacheManager(); - } - /** * redis集群配置 yml * diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/CaffeineCacheDecorator.java b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/CaffeineCacheDecorator.java new file mode 100644 index 000000000..7d3ab4266 --- /dev/null +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/CaffeineCacheDecorator.java @@ -0,0 +1,89 @@ +package org.dromara.common.redis.manager; + +import cn.hutool.core.lang.Console; +import org.dromara.common.core.utils.SpringUtils; +import org.springframework.cache.Cache; + +import java.util.concurrent.Callable; + +/** + * Cache 装饰器模式(用于扩展 Caffeine 一级缓存) + * + * @author LionLi + */ +public class CaffeineCacheDecorator implements Cache { + + private static final com.github.benmanes.caffeine.cache.Cache + CAFFEINE = SpringUtils.getBean("caffeine"); + + private final Cache cache; + + public CaffeineCacheDecorator(Cache cache) { + this.cache = cache; + } + + @Override + public String getName() { + return cache.getName(); + } + + @Override + public Object getNativeCache() { + return cache.getNativeCache(); + } + + public String getUniqueKey(Object key) { + return cache.getName() + ":" + key; + } + + @Override + public ValueWrapper get(Object key) { + Object o = CAFFEINE.get(getUniqueKey(key), k -> cache.get(key)); + return (ValueWrapper) o; + } + + @SuppressWarnings("unchecked") + public T get(Object key, Class type) { + Object o = CAFFEINE.get(getUniqueKey(key), k -> cache.get(key, type)); + return (T) o; + } + + @Override + public void put(Object key, Object value) { + cache.put(key, value); + } + + public ValueWrapper putIfAbsent(Object key, Object value) { + return cache.putIfAbsent(key, value); + } + + @Override + public void evict(Object key) { + evictIfPresent(key); + } + + public boolean evictIfPresent(Object key) { + boolean b = cache.evictIfPresent(key); + if (b) { + CAFFEINE.invalidate(getUniqueKey(key)); + } + return b; + } + + @Override + public void clear() { + cache.clear(); + } + + public boolean invalidate() { + return cache.invalidate(); + } + + @SuppressWarnings("unchecked") + @Override + public T get(Object key, Callable valueLoader) { + Object o = CAFFEINE.get(getUniqueKey(key), k -> cache.get(key, valueLoader)); + return (T) o; + } + +} diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/PlusSpringCacheManager.java b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/PlusSpringCacheManager.java index 08ebc7826..a48cb1422 100644 --- a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/PlusSpringCacheManager.java +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/PlusSpringCacheManager.java @@ -156,7 +156,7 @@ public class PlusSpringCacheManager implements CacheManager { private Cache createMap(String name, CacheConfig config) { RMap map = RedisUtils.getClient().getMap(name); - Cache cache = new RedissonCache(map, allowNullValues); + Cache cache = new CaffeineCacheDecorator(new RedissonCache(map, allowNullValues)); if (transactionAware) { cache = new TransactionAwareCacheDecorator(cache); } @@ -170,7 +170,7 @@ public class PlusSpringCacheManager implements CacheManager { private Cache createMapCache(String name, CacheConfig config) { RMapCache map = RedisUtils.getClient().getMapCache(name); - Cache cache = new RedissonCache(map, config, allowNullValues); + Cache cache = new CaffeineCacheDecorator(new RedissonCache(map, config, allowNullValues)); if (transactionAware) { cache = new TransactionAwareCacheDecorator(cache); } diff --git a/ruoyi-common/ruoyi-common-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index 59192c5ce..0475b19f4 100644 --- a/ruoyi-common/ruoyi-common-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/ruoyi-common/ruoyi-common-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -1 +1,2 @@ org.dromara.common.redis.config.RedisConfig +org.dromara.common.redis.config.CacheConfig diff --git a/ruoyi-common/ruoyi-common-satoken/pom.xml b/ruoyi-common/ruoyi-common-satoken/pom.xml index 01c282b63..4df7d4ded 100644 --- a/ruoyi-common/ruoyi-common-satoken/pom.xml +++ b/ruoyi-common/ruoyi-common-satoken/pom.xml @@ -36,6 +36,11 @@ sa-token-jwt + + com.github.ben-manes.caffeine + caffeine + + diff --git a/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/dao/PlusSaTokenDao.java b/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/dao/PlusSaTokenDao.java index d88596228..0664755a4 100644 --- a/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/dao/PlusSaTokenDao.java +++ b/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/dao/PlusSaTokenDao.java @@ -2,26 +2,42 @@ package org.dromara.common.satoken.core.dao; import cn.dev33.satoken.dao.SaTokenDao; import cn.dev33.satoken.util.SaFoxUtil; +import cn.hutool.core.lang.Console; +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; import org.dromara.common.redis.utils.RedisUtils; import java.time.Duration; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.concurrent.TimeUnit; /** * Sa-Token持久层接口(使用框架自带RedisUtils实现 协议统一) + *

+ * 采用 caffeine + redis 多级缓存 优化并发查询效率 * * @author Lion Li */ public class PlusSaTokenDao implements SaTokenDao { + private static final Cache CAFFEINE = Caffeine.newBuilder() + // 设置最后一次写入或访问后经过固定时间过期 + .expireAfterWrite(5, TimeUnit.SECONDS) + // 初始的缓存空间大小 + .initialCapacity(100) + // 缓存的最大条数 + .maximumSize(1000) + .build(); + /** * 获取Value,如无返空 */ @Override public String get(String key) { - return RedisUtils.getCacheObject(key); + Object o = CAFFEINE.get(key, k -> RedisUtils.getCacheObject(key)); + return (String) o; } /** @@ -38,6 +54,7 @@ public class PlusSaTokenDao implements SaTokenDao { } else { RedisUtils.setCacheObject(key, value, Duration.ofSeconds(timeout)); } + CAFFEINE.put(key, value); } /** @@ -47,6 +64,7 @@ public class PlusSaTokenDao implements SaTokenDao { public void update(String key, String value) { if (RedisUtils.hasKey(key)) { RedisUtils.setCacheObject(key, value, true); + CAFFEINE.put(key, value); } } @@ -81,7 +99,8 @@ public class PlusSaTokenDao implements SaTokenDao { */ @Override public Object getObject(String key) { - return RedisUtils.getCacheObject(key); + Object o = CAFFEINE.get(key, k -> RedisUtils.getCacheObject(key)); + return o; } /** @@ -98,6 +117,7 @@ public class PlusSaTokenDao implements SaTokenDao { } else { RedisUtils.setCacheObject(key, object, Duration.ofSeconds(timeout)); } + CAFFEINE.put(key, object); } /** @@ -107,6 +127,7 @@ public class PlusSaTokenDao implements SaTokenDao { public void updateObject(String key, Object object) { if (RedisUtils.hasKey(key)) { RedisUtils.setCacheObject(key, object, true); + CAFFEINE.put(key, object); } } @@ -139,10 +160,14 @@ public class PlusSaTokenDao implements SaTokenDao { /** * 搜索数据 */ + @SuppressWarnings("unchecked") @Override public List searchData(String prefix, String keyword, int start, int size, boolean sortType) { - Collection keys = RedisUtils.keys(prefix + "*" + keyword + "*"); - List list = new ArrayList<>(keys); - return SaFoxUtil.searchList(list, start, size, sortType); + String keyStr = prefix + "*" + keyword + "*"; + return (List) CAFFEINE.get(keyStr, k -> { + Collection keys = RedisUtils.keys(keyStr); + List list = new ArrayList<>(keys); + return SaFoxUtil.searchList(list, start, size, sortType); + }); } } diff --git a/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java b/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java index 8488ac199..ce3d34451 100644 --- a/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java +++ b/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java @@ -1,7 +1,5 @@ package org.dromara.common.satoken.utils; -import cn.dev33.satoken.context.SaHolder; -import cn.dev33.satoken.context.model.SaStorage; import cn.dev33.satoken.session.SaSession; import cn.dev33.satoken.stp.SaLoginModel; import cn.dev33.satoken.stp.StpUtil; @@ -15,7 +13,6 @@ import org.dromara.common.core.domain.model.LoginUser; import org.dromara.common.core.enums.UserType; import java.util.Set; -import java.util.function.Supplier; /** * 登录鉴权助手 @@ -35,9 +32,10 @@ public class LoginHelper { public static final String LOGIN_USER_KEY = "loginUser"; public static final String TENANT_KEY = "tenantId"; public static final String USER_KEY = "userId"; + public static final String USER_NAME_KEY = "userName"; public static final String DEPT_KEY = "deptId"; + public static final String DEPT_NAME_KEY = "deptName"; public static final String CLIENT_KEY = "clientid"; - public static final String TENANT_ADMIN_KEY = "isTenantAdmin"; /** * 登录系统 基于 设备类型 @@ -47,11 +45,6 @@ public class LoginHelper { * @param model 配置参数 */ public static void login(LoginUser loginUser, SaLoginModel model) { - SaStorage storage = SaHolder.getStorage(); - storage.set(LOGIN_USER_KEY, loginUser); - storage.set(TENANT_KEY, loginUser.getTenantId()); - storage.set(USER_KEY, loginUser.getUserId()); - storage.set(DEPT_KEY, loginUser.getDeptId()); model = ObjectUtil.defaultIfNull(model, new SaLoginModel()); StpUtil.login(loginUser.getLoginId(), model.setExtra(TENANT_KEY, loginUser.getTenantId()) @@ -66,13 +59,11 @@ public class LoginHelper { * 获取用户(多级缓存) */ public static LoginUser getLoginUser() { - return (LoginUser) getStorageIfAbsentSet(LOGIN_USER_KEY, () -> { - SaSession session = StpUtil.getTokenSession(); - if (ObjectUtil.isNull(session)) { - return null; - } - return session.get(LOGIN_USER_KEY); - }); + SaSession session = StpUtil.getTokenSession(); + if (ObjectUtil.isNull(session)) { + return null; + } + return (LoginUser) session.get(LOGIN_USER_KEY); } /** @@ -90,7 +81,7 @@ public class LoginHelper { * 获取用户id */ public static Long getUserId() { - return Convert.toLong(getExtra(USER_KEY)); + return Convert.toLong(getExtra(USER_KEY)); } /** @@ -107,8 +98,18 @@ public class LoginHelper { return Convert.toLong(getExtra(DEPT_KEY)); } + /** + * 获取当前 Token 的扩展信息 + * + * @param key 键值 + * @return 对应的扩展数据 + */ private static Object getExtra(String key) { - return getStorageIfAbsentSet(key, () -> StpUtil.getExtra(key)); + try { + return StpUtil.getExtra(key); + } catch (Exception e) { + return null; + } } /** @@ -136,12 +137,17 @@ public class LoginHelper { return UserConstants.SUPER_ADMIN_ID.equals(userId); } + /** + * 是否为超级管理员 + * + * @return 结果 + */ public static boolean isSuperAdmin() { return isSuperAdmin(getUserId()); } /** - * 是否为超级管理员 + * 是否为租户管理员 * * @param rolePermission 角色权限标识组 * @return 结果 @@ -150,27 +156,22 @@ public class LoginHelper { return rolePermission.contains(TenantConstants.TENANT_ADMIN_ROLE_KEY); } + /** + * 是否为租户管理员 + * + * @return 结果 + */ public static boolean isTenantAdmin() { - Object value = getStorageIfAbsentSet(TENANT_ADMIN_KEY, () -> { - return isTenantAdmin(getLoginUser().getRolePermission()); - }); - return Convert.toBool(value); + return Convert.toBool(isTenantAdmin(getLoginUser().getRolePermission())); } + /** + * 检查当前用户是否已登录 + * + * @return 结果 + */ public static boolean isLogin() { return getLoginUser() != null; } - public static Object getStorageIfAbsentSet(String key, Supplier handle) { - try { - Object obj = SaHolder.getStorage().get(key); - if (ObjectUtil.isNull(obj)) { - obj = handle.get(); - SaHolder.getStorage().set(key, obj); - } - return obj; - } catch (Exception e) { - return null; - } - } } diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java b/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java index 63d7eb15b..b9283e038 100644 --- a/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java +++ b/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java @@ -4,14 +4,14 @@ import cn.dev33.satoken.exception.NotLoginException; import cn.dev33.satoken.interceptor.SaInterceptor; import cn.dev33.satoken.router.SaRouter; import cn.dev33.satoken.stp.StpUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.dromara.common.core.utils.ServletUtils; import org.dromara.common.core.utils.SpringUtils; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.common.security.config.properties.SecurityProperties; import org.dromara.common.security.handler.AllUrlHandler; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; @@ -38,35 +38,35 @@ public class SecurityConfig implements WebMvcConfigurer { public void addInterceptors(InterceptorRegistry registry) { // 注册路由拦截器,自定义验证规则 registry.addInterceptor(new SaInterceptor(handler -> { - AllUrlHandler allUrlHandler = SpringUtils.getBean(AllUrlHandler.class); - // 登录验证 -- 排除多个路径 - SaRouter - // 获取所有的 - .match(allUrlHandler.getUrls()) - // 对未排除的路径进行检查 - .check(() -> { - // 检查是否登录 是否有token - StpUtil.checkLogin(); + AllUrlHandler allUrlHandler = SpringUtils.getBean(AllUrlHandler.class); + // 登录验证 -- 排除多个路径 + SaRouter + // 获取所有的 + .match(allUrlHandler.getUrls()) + // 对未排除的路径进行检查 + .check(() -> { + // 检查是否登录 是否有token + StpUtil.checkLogin(); - // 检查 header 与 param 里的 clientid 与 token 里的是否一致 - String headerCid = ServletUtils.getRequest().getHeader(LoginHelper.CLIENT_KEY); - String paramCid = ServletUtils.getParameter(LoginHelper.CLIENT_KEY); - String clientId = StpUtil.getExtra(LoginHelper.CLIENT_KEY).toString(); - if (!StringUtils.equalsAny(clientId, headerCid, paramCid)) { - // token 无效 - throw NotLoginException.newInstance(StpUtil.getLoginType(), - "-100", "客户端ID与Token不匹配", - StpUtil.getTokenValue()); - } + // 检查 header 与 param 里的 clientid 与 token 里的是否一致 + String headerCid = ServletUtils.getRequest().getHeader(LoginHelper.CLIENT_KEY); + String paramCid = ServletUtils.getParameter(LoginHelper.CLIENT_KEY); + String clientId = StpUtil.getExtra(LoginHelper.CLIENT_KEY).toString(); + if (!StringUtils.equalsAny(clientId, headerCid, paramCid)) { + // token 无效 + throw NotLoginException.newInstance(StpUtil.getLoginType(), + "-100", "客户端ID与Token不匹配", + StpUtil.getTokenValue()); + } - // 有效率影响 用于临时测试 - // if (log.isDebugEnabled()) { - // log.info("剩余有效时间: {}", StpUtil.getTokenTimeout()); - // log.info("临时有效时间: {}", StpUtil.getTokenActivityTimeout()); - // } + // 有效率影响 用于临时测试 + // if (log.isDebugEnabled()) { + // log.info("剩余有效时间: {}", StpUtil.getTokenTimeout()); + // log.info("临时有效时间: {}", StpUtil.getTokenActivityTimeout()); + // } - }); - })).addPathPatterns("/**") + }); + })).addPathPatterns("/**") // 排除不需要拦截的路径 .excludePathPatterns(securityProperties.getExcludes()); } diff --git a/ruoyi-common/ruoyi-common-sms/pom.xml b/ruoyi-common/ruoyi-common-sms/pom.xml index c50f222ac..932cb9d52 100644 --- a/ruoyi-common/ruoyi-common-sms/pom.xml +++ b/ruoyi-common/ruoyi-common-sms/pom.xml @@ -20,13 +20,12 @@ org.dromara.sms4j sms4j-spring-boot-starter - - - - com.alibaba - fastjson - - + + + + + org.dromara + ruoyi-common-redis diff --git a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/SmsAutoConfiguration.java b/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/SmsAutoConfiguration.java index 29f60fc50..1e88407e8 100644 --- a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/SmsAutoConfiguration.java +++ b/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/SmsAutoConfiguration.java @@ -1,14 +1,24 @@ package org.dromara.common.sms.config; +import org.dromara.common.sms.core.dao.PlusSmsDao; +import org.dromara.sms4j.api.dao.SmsDao; import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; /** - * 短信配置类(暂时没用 预留扩展) + * 短信配置类 * - * @author Lion Li - * @version 4.2.0 + * @author Feng */ -@AutoConfiguration +@AutoConfiguration(after = {RedisAutoConfiguration.class}) public class SmsAutoConfiguration { + @Primary + @Bean + public SmsDao smsDao() { + return new PlusSmsDao(); + } + } diff --git a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/dao/PlusSmsDao.java b/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/dao/PlusSmsDao.java new file mode 100644 index 000000000..91d8d243a --- /dev/null +++ b/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/dao/PlusSmsDao.java @@ -0,0 +1,72 @@ +package org.dromara.common.sms.core.dao; + +import org.dromara.common.core.constant.GlobalConstants; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.sms4j.api.dao.SmsDao; + +import java.time.Duration; + +/** + * SmsDao缓存配置 (使用框架自带RedisUtils实现 协议统一) + *

主要用于短信重试和拦截的缓存 + * + * @author Feng + */ +public class PlusSmsDao implements SmsDao { + + /** + * 存储 + * + * @param key 键 + * @param value 值 + * @param cacheTime 缓存时间(单位:秒) + */ + @Override + public void set(String key, Object value, long cacheTime) { + RedisUtils.setCacheObject(GlobalConstants.GLOBAL_REDIS_KEY + key, value, Duration.ofSeconds(cacheTime)); + } + + /** + * 存储 + * + * @param key 键 + * @param value 值 + */ + @Override + public void set(String key, Object value) { + RedisUtils.setCacheObject(GlobalConstants.GLOBAL_REDIS_KEY + key, value, true); + } + + /** + * 读取 + * + * @param key 键 + * @return 值 + */ + @Override + public Object get(String key) { + return RedisUtils.getCacheObject(GlobalConstants.GLOBAL_REDIS_KEY + key); + } + + /** + * remove + *

根据key移除缓存 + * + * @param key 缓存键 + * @return 被删除的value + * @author :Wind + */ + @Override + public Object remove(String key) { + return RedisUtils.deleteObject(GlobalConstants.GLOBAL_REDIS_KEY + key); + } + + /** + * 清空 + */ + @Override + public void clean() { + RedisUtils.deleteObject(GlobalConstants.GLOBAL_REDIS_KEY + "sms:"); + } + +} diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialLoginConfigProperties.java b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialLoginConfigProperties.java index 76be234c6..5f49d9c27 100644 --- a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialLoginConfigProperties.java +++ b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialLoginConfigProperties.java @@ -2,6 +2,8 @@ package org.dromara.common.social.config.properties; import lombok.Data; +import java.util.List; + /** * 社交登录配置 * @@ -65,4 +67,9 @@ public class SocialLoginConfigProperties { */ private String serverUrl; + /** + * 请求范围 + */ + private List scopes; + } diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialProperties.java b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialProperties.java index 1beb7d042..1487a6a92 100644 --- a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialProperties.java +++ b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialProperties.java @@ -16,11 +16,6 @@ import java.util.Map; @ConfigurationProperties(prefix = "justauth") public class SocialProperties { - /** - * 是否启用 - */ - private Boolean enabled; - /** * 授权类型 */ diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/topiam/AuthTopIamRequest.java b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/topiam/AuthTopIamRequest.java new file mode 100644 index 000000000..13649f9fd --- /dev/null +++ b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/topiam/AuthTopIamRequest.java @@ -0,0 +1,100 @@ +package org.dromara.common.social.topiam; + +import cn.hutool.core.lang.Dict; +import cn.hutool.core.util.StrUtil; +import com.xkcoding.http.support.HttpHeader; +import lombok.extern.slf4j.Slf4j; +import me.zhyd.oauth.cache.AuthStateCache; +import me.zhyd.oauth.config.AuthConfig; +import me.zhyd.oauth.exception.AuthException; +import me.zhyd.oauth.model.AuthCallback; +import me.zhyd.oauth.model.AuthToken; +import me.zhyd.oauth.model.AuthUser; +import me.zhyd.oauth.request.AuthDefaultRequest; +import me.zhyd.oauth.utils.HttpUtils; +import me.zhyd.oauth.utils.UrlBuilder; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.json.utils.JsonUtils; + +import static org.dromara.common.social.topiam.AuthTopiamSource.TOPIAM; + +/** + * TopIAM 认证请求 + * + * @author xlsea + * @since 2024-01-06 + */ +@Slf4j +public class AuthTopIamRequest extends AuthDefaultRequest { + + public static final String SERVER_URL = SpringUtils.getProperty("justauth.type.topiam.server-url"); + + /** + * 设定归属域 + */ + public AuthTopIamRequest(AuthConfig config) { + super(config, TOPIAM); + } + + public AuthTopIamRequest(AuthConfig config, AuthStateCache authStateCache) { + super(config, TOPIAM, authStateCache); + } + + @Override + protected AuthToken getAccessToken(AuthCallback authCallback) { + String body = doPostAuthorizationCode(authCallback.getCode()); + Dict object = JsonUtils.parseMap(body); + checkResponse(object); + return AuthToken.builder() + .accessToken(object.getStr("access_token")) + .refreshToken(object.getStr("refresh_token")) + .idToken(object.getStr("id_token")) + .tokenType(object.getStr("token_type")) + .scope(object.getStr("scope")) + .build(); + } + + @Override + protected AuthUser getUserInfo(AuthToken authToken) { + String body = doGetUserInfo(authToken); + Dict object = JsonUtils.parseMap(body); + checkResponse(object); + return AuthUser.builder() + .uuid(object.getStr("sub")) + .username(object.getStr("preferred_username")) + .nickname(object.getStr("nickname")) + .avatar(object.getStr("picture")) + .email(object.getStr("email")) + .token(authToken) + .source(source.toString()) + .build(); + } + + + @Override + protected String doGetUserInfo(AuthToken authToken) { + return new HttpUtils(config.getHttpConfig()).get(source.userInfo(), null, new HttpHeader() + .add("Content-Type", "application/json") + .add("Authorization", "Bearer " + authToken.getAccessToken()), false).getBody(); + } + + + @Override + public String authorize(String state) { + return UrlBuilder.fromBaseUrl(super.authorize(state)) + .queryParam("scope", StrUtil.join("%20", config.getScopes())) + .build(); + } + + public static void checkResponse(Dict object) { + // oauth/token 验证异常 + if (object.containsKey("error")) { + throw new AuthException(object.getStr("error_description")); + } + // user 验证异常 + if (object.containsKey("message")) { + throw new AuthException(object.getStr("message")); + } + } + +} diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/topiam/AuthTopiamSource.java b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/topiam/AuthTopiamSource.java new file mode 100644 index 000000000..e47d6c640 --- /dev/null +++ b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/topiam/AuthTopiamSource.java @@ -0,0 +1,51 @@ +package org.dromara.common.social.topiam; + +import me.zhyd.oauth.config.AuthSource; +import me.zhyd.oauth.request.AuthDefaultRequest; + +/** + * Oauth2 默认接口说明 + * + * @author xlsea + * @since 2024-01-06 + */ +public enum AuthTopiamSource implements AuthSource { + + /** + * 测试 + */ + TOPIAM { + /** + * 授权的api + */ + @Override + public String authorize() { + return AuthTopIamRequest.SERVER_URL + "/oauth2/auth"; + } + + /** + * 获取accessToken的api + */ + @Override + public String accessToken() { + return AuthTopIamRequest.SERVER_URL + "/oauth2/token"; + } + + /** + * 获取用户信息的api + */ + @Override + public String userInfo() { + return AuthTopIamRequest.SERVER_URL + "/oauth2/userinfo"; + } + + /** + * 平台对应的 AuthRequest 实现类,必须继承自 {@link AuthDefaultRequest} + */ + @Override + public Class getTargetClass() { + return AuthTopIamRequest.class; + } + + } +} diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java index 51b7e13d7..04f621489 100644 --- a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java +++ b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java @@ -11,6 +11,7 @@ import org.dromara.common.core.utils.SpringUtils; import org.dromara.common.social.config.properties.SocialLoginConfigProperties; import org.dromara.common.social.config.properties.SocialProperties; import org.dromara.common.social.maxkey.AuthMaxKeyRequest; +import org.dromara.common.social.topiam.AuthTopIamRequest; /** * 认证授权工具类 @@ -38,7 +39,8 @@ public class SocialUtils { AuthConfig.AuthConfigBuilder builder = AuthConfig.builder() .clientId(obj.getClientId()) .clientSecret(obj.getClientSecret()) - .redirectUri(obj.getRedirectUri()); + .redirectUri(obj.getRedirectUri()) + .scopes(obj.getScopes()); return switch (source.toLowerCase()) { case "dingtalk" -> new AuthDingTalkRequest(builder.build(), STATE_CACHE); case "baidu" -> new AuthBaiduRequest(builder.build(), STATE_CACHE); @@ -63,6 +65,7 @@ public class SocialUtils { case "wechat_mp" -> new AuthWeChatMpRequest(builder.build(), STATE_CACHE); case "aliyun" -> new AuthAliyunRequest(builder.build(), STATE_CACHE); case "maxkey" -> new AuthMaxKeyRequest(builder.build(), STATE_CACHE); + case "topiam" -> new AuthTopIamRequest(builder.build(), STATE_CACHE); default -> throw new AuthException("未获取到有效的Auth配置"); }; } diff --git a/ruoyi-common/ruoyi-common-tenant/pom.xml b/ruoyi-common/ruoyi-common-tenant/pom.xml index 2b87bf961..8e1a6ab1e 100644 --- a/ruoyi-common/ruoyi-common-tenant/pom.xml +++ b/ruoyi-common/ruoyi-common-tenant/pom.xml @@ -19,6 +19,7 @@ org.dromara ruoyi-common-mybatis + true @@ -26,11 +27,6 @@ ruoyi-common-redis - - com.alibaba - transmittable-thread-local - - diff --git a/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/config/TenantConfig.java b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/config/TenantConfig.java index 8610641dd..0ff39fdc0 100644 --- a/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/config/TenantConfig.java +++ b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/config/TenantConfig.java @@ -2,8 +2,6 @@ package org.dromara.common.tenant.config; import cn.dev33.satoken.dao.SaTokenDao; import cn.hutool.core.util.ObjectUtil; -import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; -import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; import org.dromara.common.core.utils.reflect.ReflectUtils; import org.dromara.common.mybatis.config.MybatisPlusConfig; @@ -24,9 +22,6 @@ import org.springframework.cache.CacheManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Primary; -import java.util.ArrayList; -import java.util.List; - /** * 租户配置类 * @@ -37,23 +32,10 @@ import java.util.List; @ConditionalOnProperty(value = "tenant.enable", havingValue = "true") public class TenantConfig { - /** - * 初始化租户配置 - */ - @Bean - public boolean tenantInit(MybatisPlusInterceptor mybatisPlusInterceptor, - TenantProperties tenantProperties) { - List interceptors = new ArrayList<>(); - // 多租户插件 必须放到第一位 - interceptors.add(tenantLineInnerInterceptor(tenantProperties)); - interceptors.addAll(mybatisPlusInterceptor.getInterceptors()); - mybatisPlusInterceptor.setInterceptors(interceptors); - return true; - } - /** * 多租户插件 */ + @Bean public TenantLineInnerInterceptor tenantLineInnerInterceptor(TenantProperties tenantProperties) { return new TenantLineInnerInterceptor(new PlusTenantLineHandler(tenantProperties)); } diff --git a/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/handle/TenantKeyPrefixHandler.java b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/handle/TenantKeyPrefixHandler.java index 14dad1a71..947539863 100644 --- a/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/handle/TenantKeyPrefixHandler.java +++ b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/handle/TenantKeyPrefixHandler.java @@ -1,5 +1,6 @@ package org.dromara.common.tenant.handle; +import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper; import lombok.extern.slf4j.Slf4j; import org.dromara.common.core.constant.GlobalConstants; import org.dromara.common.core.utils.StringUtils; @@ -26,6 +27,9 @@ public class TenantKeyPrefixHandler extends KeyPrefixHandler { if (StringUtils.isBlank(name)) { return null; } + if (InterceptorIgnoreHelper.willIgnoreTenantLine("")) { + return super.map(name); + } if (StringUtils.contains(name, GlobalConstants.GLOBAL_REDIS_KEY)) { return super.map(name); } @@ -49,6 +53,9 @@ public class TenantKeyPrefixHandler extends KeyPrefixHandler { if (StringUtils.isBlank(unmap)) { return null; } + if (InterceptorIgnoreHelper.willIgnoreTenantLine("")) { + return super.unmap(name); + } if (StringUtils.contains(name, GlobalConstants.GLOBAL_REDIS_KEY)) { return super.unmap(name); } diff --git a/ruoyi-common/ruoyi-common-web/pom.xml b/ruoyi-common/ruoyi-common-web/pom.xml index 293c52229..b250fa9d0 100644 --- a/ruoyi-common/ruoyi-common-web/pom.xml +++ b/ruoyi-common/ruoyi-common-web/pom.xml @@ -57,11 +57,6 @@ cn.hutool hutool-crypto - - - com.alibaba - transmittable-thread-local - diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/CaptchaConfig.java b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/CaptchaConfig.java index 9225a51bf..650517ed1 100644 --- a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/CaptchaConfig.java +++ b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/CaptchaConfig.java @@ -23,7 +23,7 @@ public class CaptchaConfig { private static final int WIDTH = 160; private static final int HEIGHT = 60; - private static final Color BACKGROUND = Color.PINK; + private static final Color BACKGROUND = Color.LIGHT_GRAY; private static final Font FONT = new Font("Arial", Font.BOLD, 48); /** diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/UndertowConfig.java b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/UndertowConfig.java index 421ce6d14..0f7892861 100644 --- a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/UndertowConfig.java +++ b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/UndertowConfig.java @@ -2,9 +2,11 @@ package org.dromara.common.web.config; import io.undertow.server.DefaultByteBufferPool; import io.undertow.websockets.jsr.WebSocketDeploymentInfo; +import org.dromara.common.core.utils.SpringUtils; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory; import org.springframework.boot.web.server.WebServerFactoryCustomizer; +import org.springframework.core.task.VirtualThreadTaskExecutor; /** * Undertow 自定义配置 @@ -24,6 +26,12 @@ public class UndertowConfig implements WebServerFactoryCustomizer invokeTimeTL = new TransmittableThreadLocal<>(); + private final static ThreadLocal KEY_CACHE = new ThreadLocal<>(); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { @@ -56,7 +55,7 @@ public class PlusWebInvokeTimeInterceptor implements HandlerInterceptor { } StopWatch stopWatch = new StopWatch(); - invokeTimeTL.set(stopWatch); + KEY_CACHE.set(stopWatch); stopWatch.start(); } return true; @@ -70,10 +69,10 @@ public class PlusWebInvokeTimeInterceptor implements HandlerInterceptor { @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { if (!prodProfile.equals(SpringUtils.getActiveProfile())) { - StopWatch stopWatch = invokeTimeTL.get(); + StopWatch stopWatch = KEY_CACHE.get(); stopWatch.stop(); log.info("[PLUS]结束请求 => URL[{}],耗时:[{}]毫秒", request.getMethod() + " " + request.getRequestURI(), stopWatch.getTime()); - invokeTimeTL.remove(); + KEY_CACHE.remove(); } } diff --git a/ruoyi-extend/pom.xml b/ruoyi-extend/pom.xml index f5348cc13..0e9533f18 100644 --- a/ruoyi-extend/pom.xml +++ b/ruoyi-extend/pom.xml @@ -14,6 +14,7 @@ ruoyi-monitor-admin ruoyi-powerjob-server + ruoyi-easyretry-server diff --git a/ruoyi-extend/ruoyi-easyretry-server/Dockerfile b/ruoyi-extend/ruoyi-easyretry-server/Dockerfile new file mode 100644 index 000000000..7ad0a0776 --- /dev/null +++ b/ruoyi-extend/ruoyi-easyretry-server/Dockerfile @@ -0,0 +1,18 @@ +#FROM findepi/graalvm:java17-native +FROM openjdk:17.0.2-oraclelinux8 + +MAINTAINER Lion Li + +RUN mkdir -p /ruoyi/easyretry/logs + +WORKDIR /ruoyi/easyretry + +ENV LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS="-Xms512m -Xmx1024m" + +EXPOSE 8800 +EXPOSE 1788 + +ADD ./target/ruoyi-easyretry-server.jar ./app.jar + +ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -jar app.jar \ + -XX:+HeapDumpOnOutOfMemoryError -Xlog:gc*,:time,tags,level -XX:+UseZGC ${JAVA_OPTS} diff --git a/ruoyi-extend/ruoyi-easyretry-server/pom.xml b/ruoyi-extend/ruoyi-easyretry-server/pom.xml new file mode 100644 index 000000000..4ea4d743b --- /dev/null +++ b/ruoyi-extend/ruoyi-easyretry-server/pom.xml @@ -0,0 +1,46 @@ + + + + org.dromara + ruoyi-extend + ${revision} + + 4.0.0 + jar + ruoyi-easyretry-server + + + + com.aizuda + easy-retry-server-starter + ${easyretry.version} + + + + de.codecentric + spring-boot-admin-starter-client + ${spring-boot-admin.version} + + + + + ${project.artifactId} + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + + + repackage + + + + + + + + diff --git a/ruoyi-extend/ruoyi-easyretry-server/src/main/java/org/dromara/easyretry/EasyRetryServerApplication.java b/ruoyi-extend/ruoyi-easyretry-server/src/main/java/org/dromara/easyretry/EasyRetryServerApplication.java new file mode 100644 index 000000000..9d01bc05b --- /dev/null +++ b/ruoyi-extend/ruoyi-easyretry-server/src/main/java/org/dromara/easyretry/EasyRetryServerApplication.java @@ -0,0 +1,18 @@ +package org.dromara.easyretry; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * EasyRetry Server 启动程序 + * + * @author dhb52 + */ +@SpringBootApplication +public class EasyRetryServerApplication { + + public static void main(String[] args) { + SpringApplication.run(com.aizuda.easy.retry.server.EasyRetryServerApplication.class, args); + } + +} diff --git a/ruoyi-extend/ruoyi-easyretry-server/src/main/resources/application-dev.yml b/ruoyi-extend/ruoyi-easyretry-server/src/main/resources/application-dev.yml new file mode 100644 index 000000000..c151a6195 --- /dev/null +++ b/ruoyi-extend/ruoyi-easyretry-server/src/main/resources/application-dev.yml @@ -0,0 +1,50 @@ +spring: + datasource: + type: com.zaxxer.hikari.HikariDataSource + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true + username: root + password: root + hikari: + connection-timeout: 30000 + validation-timeout: 5000 + minimum-idle: 10 + maximum-pool-size: 20 + idle-timeout: 600000 + max-lifetime: 900000 + keepaliveTime: 30000 + +--- # easy-retry 服务端配置 +easy-retry: + # 拉取重试数据的每批次的大小 + retry-pull-page-size: 1000 + # 拉取重试数据的每批次的大小 + job-pull-page-size: 1000 + # 服务端 netty 端口 + netty-port: 1788 + # 重试和死信表的分区总数 + total-partition: 2 + # 一个客户端每秒最多接收的重试数量指令 + limiter: 1000 + # 号段模式下步长配置 + step: 100 + # 日志保存时间(单位: day) + log-storage: 90 + # 回调配置 + callback: + #回调最大执行次数 + max-count: 288 + #间隔时间 + trigger-interval: 900 + mode: all + retry-max-pull-count: 10 + +--- # 监控中心配置 +spring.boot.admin.client: + # 增加客户端开关 + enabled: true + url: http://localhost:9090/admin + instance: + service-host-type: IP + username: ruoyi + password: 123456 diff --git a/ruoyi-extend/ruoyi-easyretry-server/src/main/resources/application-prod.yml b/ruoyi-extend/ruoyi-easyretry-server/src/main/resources/application-prod.yml new file mode 100644 index 000000000..c151a6195 --- /dev/null +++ b/ruoyi-extend/ruoyi-easyretry-server/src/main/resources/application-prod.yml @@ -0,0 +1,50 @@ +spring: + datasource: + type: com.zaxxer.hikari.HikariDataSource + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true + username: root + password: root + hikari: + connection-timeout: 30000 + validation-timeout: 5000 + minimum-idle: 10 + maximum-pool-size: 20 + idle-timeout: 600000 + max-lifetime: 900000 + keepaliveTime: 30000 + +--- # easy-retry 服务端配置 +easy-retry: + # 拉取重试数据的每批次的大小 + retry-pull-page-size: 1000 + # 拉取重试数据的每批次的大小 + job-pull-page-size: 1000 + # 服务端 netty 端口 + netty-port: 1788 + # 重试和死信表的分区总数 + total-partition: 2 + # 一个客户端每秒最多接收的重试数量指令 + limiter: 1000 + # 号段模式下步长配置 + step: 100 + # 日志保存时间(单位: day) + log-storage: 90 + # 回调配置 + callback: + #回调最大执行次数 + max-count: 288 + #间隔时间 + trigger-interval: 900 + mode: all + retry-max-pull-count: 10 + +--- # 监控中心配置 +spring.boot.admin.client: + # 增加客户端开关 + enabled: true + url: http://localhost:9090/admin + instance: + service-host-type: IP + username: ruoyi + password: 123456 diff --git a/ruoyi-extend/ruoyi-easyretry-server/src/main/resources/application.yml b/ruoyi-extend/ruoyi-easyretry-server/src/main/resources/application.yml new file mode 100644 index 000000000..b6d8998e8 --- /dev/null +++ b/ruoyi-extend/ruoyi-easyretry-server/src/main/resources/application.yml @@ -0,0 +1,40 @@ +server: + port: 8800 + servlet: + context-path: /easy-retry + +spring: + application: + name: ruoyi-easyretry-server + profiles: + active: @profiles.active@ + web: + resources: + static-locations: classpath:admin/ + +mybatis-plus: + typeAliasesPackage: com.aizuda.easy.retry.template.datasource.persistence.po + global-config: + db-config: + table-prefix: er_ + where-strategy: NOT_EMPTY + capital-mode: false + logic-delete-value: 1 + logic-not-delete-value: 0 + configuration: + map-underscore-to-camel-case: true + cache-enabled: true + +logging: + config: classpath:logback-plus.xml + +management: + endpoints: + web: + exposure: + include: '*' + endpoint: + health: + show-details: ALWAYS + logfile: + external-file: ./logs/ruoyi-easyretry-server/console.log diff --git a/ruoyi-extend/ruoyi-easyretry-server/src/main/resources/banner.txt b/ruoyi-extend/ruoyi-easyretry-server/src/main/resources/banner.txt new file mode 100644 index 000000000..869a4209c --- /dev/null +++ b/ruoyi-extend/ruoyi-easyretry-server/src/main/resources/banner.txt @@ -0,0 +1,10 @@ +Application Version: ${revision} +Spring Boot Version: ${spring-boot.version} + _ + | | + ___ __ _ ___ _ _ ______ _ __ ___| |_ _ __ _ _ ______ ___ ___ _ ____ _____ _ __ + / _ \/ _` / __| | | |______| '__/ _ \ __| '__| | | |______/ __|/ _ \ '__\ \ / / _ \ '__| +| __/ (_| \__ \ |_| | | | | __/ |_| | | |_| | \__ \ __/ | \ V / __/ | + \___|\__,_|___/\__, | |_| \___|\__|_| \__, | |___/\___|_| \_/ \___|_| + __/ | __/ | + |___/ |___/ diff --git a/ruoyi-extend/ruoyi-easyretry-server/src/main/resources/logback-plus.xml b/ruoyi-extend/ruoyi-easyretry-server/src/main/resources/logback-plus.xml new file mode 100644 index 000000000..bcd3abc4c --- /dev/null +++ b/ruoyi-extend/ruoyi-easyretry-server/src/main/resources/logback-plus.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + ${console.log.pattern} + utf-8 + + + + + + ${log.path}/console.log + + + ${log.path}/console.%d{yyyy-MM-dd}.log + + 1 + + + ${log.pattern} + utf-8 + + + + INFO + + + + + ${log.path}/info.log + + ${log.path}/info.%d{yyyy-MM-dd}.log + 60 + + + ${log.pattern} + + + INFO + ACCEPT + DENY + + + + + ${log.path}/error.log + + ${log.path}/error.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + ERROR + ACCEPT + DENY + + + + + 100 + 1024 + + + + + 100 + 1024 + + + + + + + + + + + + + + + diff --git a/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/config/AdminServerConfig.java b/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/config/AdminServerConfig.java index 1f70c75f7..53d248e39 100644 --- a/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/config/AdminServerConfig.java +++ b/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/config/AdminServerConfig.java @@ -3,7 +3,7 @@ package org.dromara.monitor.admin.config; import de.codecentric.boot.admin.server.config.EnableAdminServer; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration; -import org.springframework.boot.task.TaskExecutorBuilder; +import org.springframework.boot.task.ThreadPoolTaskExecutorBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Lazy; @@ -23,7 +23,7 @@ public class AdminServerConfig { @Lazy @Bean(name = TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME) @ConditionalOnMissingBean(Executor.class) - public ThreadPoolTaskExecutor applicationTaskExecutor(TaskExecutorBuilder builder) { + public ThreadPoolTaskExecutor applicationTaskExecutor(ThreadPoolTaskExecutorBuilder builder) { return builder.build(); } diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/SmsController.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/SmsController.java index fb1973148..b993f60b5 100644 --- a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/SmsController.java +++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/SmsController.java @@ -5,7 +5,6 @@ import org.dromara.common.core.domain.R; import org.dromara.sms4j.api.SmsBlend; import org.dromara.sms4j.api.entity.SmsResponse; import org.dromara.sms4j.core.factory.SmsFactory; -import org.dromara.sms4j.provider.enumerate.SupplierType; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -25,7 +24,6 @@ import java.util.LinkedHashMap; @RestController @RequestMapping("/demo/sms") public class SmsController { - /** * 发送短信Aliyun * @@ -36,7 +34,7 @@ public class SmsController { public R sendAliyun(String phones, String templateId) { LinkedHashMap map = new LinkedHashMap<>(1); map.put("code", "1234"); - SmsBlend smsBlend = SmsFactory.createSmsBlend(SupplierType.ALIBABA); + SmsBlend smsBlend = SmsFactory.getSmsBlend("config1"); SmsResponse smsResponse = smsBlend.sendMessage(phones, templateId, map); return R.ok(smsResponse); } @@ -52,9 +50,33 @@ public class SmsController { LinkedHashMap map = new LinkedHashMap<>(1); // map.put("2", "测试测试"); map.put("1", "1234"); - SmsBlend smsBlend = SmsFactory.createSmsBlend(SupplierType.TENCENT); + SmsBlend smsBlend = SmsFactory.getSmsBlend("config2"); SmsResponse smsResponse = smsBlend.sendMessage(phones, templateId, map); return R.ok(smsResponse); } + /** + * 添加黑名单 + * + * @param phone 手机号 + */ + @GetMapping("/addBlacklist") + public R addBlacklist(String phone){ + SmsBlend smsBlend = SmsFactory.getSmsBlend("config1"); + smsBlend.joinInBlacklist(phone); + return R.ok(); + } + + /** + * 移除黑名单 + * + * @param phone 手机号 + */ + @GetMapping("/removeBlacklist") + public R removeBlacklist(String phone){ + SmsBlend smsBlend = SmsFactory.getSmsBlend("config1"); + smsBlend.removeFromBlacklist(phone); + return R.ok(); + } + } diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTableColumn.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTableColumn.java index 5ce7ad043..ebdb9930c 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTableColumn.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTableColumn.java @@ -42,7 +42,7 @@ public class GenTableColumn extends BaseEntity { /** * 列描述 */ - @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR) + @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR) private String columnComment; /** @@ -64,43 +64,43 @@ public class GenTableColumn extends BaseEntity { /** * 是否主键(1是) */ - @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR) + @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR) private String isPk; /** * 是否自增(1是) */ - @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR) + @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR) private String isIncrement; /** * 是否必填(1是) */ - @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR) + @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR) private String isRequired; /** * 是否为插入字段(1是) */ - @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR) + @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR) private String isInsert; /** * 是否编辑字段(1是) */ - @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR) + @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR) private String isEdit; /** * 是否列表字段(1是) */ - @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR) + @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR) private String isList; /** * 是否查询字段(1是) */ - @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR) + @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR) private String isQuery; /** diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/controller.java.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/controller.java.vm index 14177b5df..64389717d 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/controller.java.vm +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/controller.java.vm @@ -20,7 +20,7 @@ import org.dromara.common.excel.utils.ExcelUtil; import ${packageName}.domain.vo.${ClassName}Vo; import ${packageName}.domain.bo.${ClassName}Bo; import ${packageName}.service.I${ClassName}Service; -#if($table.crud || $table.sub) +#if($table.crud) import org.dromara.common.mybatis.core.page.TableDataInfo; #elseif($table.tree) #end @@ -44,7 +44,7 @@ public class ${ClassName}Controller extends BaseController { */ @SaCheckPermission("${permissionPrefix}:list") @GetMapping("/list") -#if($table.crud || $table.sub) +#if($table.crud) public TableDataInfo<${ClassName}Vo> list(${ClassName}Bo bo, PageQuery pageQuery) { return ${className}Service.queryPageList(bo, pageQuery); } diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/service.java.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/service.java.vm index d596a0e91..f1fa3d991 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/service.java.vm +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/service.java.vm @@ -3,7 +3,7 @@ package ${packageName}.service; import ${packageName}.domain.${ClassName}; import ${packageName}.domain.vo.${ClassName}Vo; import ${packageName}.domain.bo.${ClassName}Bo; -#if($table.crud || $table.sub) +#if($table.crud) import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.PageQuery; #end @@ -24,7 +24,7 @@ public interface I${ClassName}Service { */ ${ClassName}Vo queryById(${pkColumn.javaType} ${pkColumn.javaField}); -#if($table.crud || $table.sub) +#if($table.crud) /** * 查询${functionName}列表 */ diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm index 75a9b83a2..d603de120 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm @@ -2,7 +2,7 @@ package ${packageName}.service.impl; import org.dromara.common.core.utils.MapstructUtils; import org.dromara.common.core.utils.StringUtils; -#if($table.crud || $table.sub) +#if($table.crud) import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.PageQuery; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -41,7 +41,7 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service { return baseMapper.selectVoById(${pkColumn.javaField}); } -#if($table.crud || $table.sub) +#if($table.crud) /** * 查询${functionName}列表 */ diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm index 8b132f4ab..aaceca611 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm @@ -439,7 +439,7 @@ const submitForm = () => { } else { await add${BusinessName}(form.value).finally(() => buttonLoading.value = false); } - proxy?.#[[$modal]]#.msgSuccess("修改成功"); + proxy?.#[[$modal]]#.msgSuccess("操作成功"); dialog.visible = false; await getList(); } diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/easyretry/TestAnnoJobExecutor.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/easyretry/TestAnnoJobExecutor.java new file mode 100644 index 000000000..05c4f2fb0 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/easyretry/TestAnnoJobExecutor.java @@ -0,0 +1,23 @@ +package org.dromara.job.easyretry; + +import com.aizuda.easy.retry.client.job.core.annotation.JobExecutor; +import com.aizuda.easy.retry.client.job.core.dto.JobArgs; +import com.aizuda.easy.retry.client.model.ExecuteResult; +import com.aizuda.easy.retry.common.core.util.JsonUtil; +import com.aizuda.easy.retry.common.log.EasyRetryLog; +import org.springframework.stereotype.Component; + +/** + * @author www.byteblogs.com + * @date 2023-09-28 22:54:07 + */ +@Component +@JobExecutor(name = "testJobExecutor") +public class TestAnnoJobExecutor { + + public ExecuteResult jobExecute(JobArgs jobArgs) { + EasyRetryLog.LOCAL.info("testJobExecutor. jobArgs:{}", JsonUtil.toJsonString(jobArgs)); + EasyRetryLog.REMOTE.info("testJobExecutor. jobArgs:{}", JsonUtil.toJsonString(jobArgs)); + return ExecuteResult.success("测试成功"); + } +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/easyretry/TestClassJobExecutor.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/easyretry/TestClassJobExecutor.java new file mode 100644 index 000000000..d675cec73 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/easyretry/TestClassJobExecutor.java @@ -0,0 +1,19 @@ +package org.dromara.job.easyretry; + +import com.aizuda.easy.retry.client.job.core.dto.JobArgs; +import com.aizuda.easy.retry.client.job.core.executor.AbstractJobExecutor; +import com.aizuda.easy.retry.client.model.ExecuteResult; +import org.springframework.stereotype.Component; + +/** + * @author www.byteblogs.com + * @date 2023-09-28 22:54:07 + */ +@Component +public class TestClassJobExecutor extends AbstractJobExecutor { + + @Override + protected ExecuteResult doJobExecute(JobArgs jobArgs) { + return ExecuteResult.success("TestJobExecutor测试成功"); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java index def448d4d..9b08c2d2c 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java @@ -21,6 +21,7 @@ import org.springframework.web.bind.annotation.*; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; /** * 在线用户监控 @@ -87,4 +88,43 @@ public class SysUserOnlineController extends BaseController { } return R.ok(); } + + /** + * 获取当前用户登录在线设备 + */ + @GetMapping() + public TableDataInfo getInfo() { + // 获取指定账号 id 的 token 集合 + List tokenIds = StpUtil.getTokenValueListByLoginId(StpUtil.getLoginIdAsString()); + List userOnlineDTOList = tokenIds.stream() + .filter(token -> StpUtil.stpLogic.getTokenActiveTimeoutByToken(token) >= -1) + .map(token -> (UserOnlineDTO) RedisUtils.getCacheObject(CacheConstants.ONLINE_TOKEN_KEY + token)) + .collect(Collectors.toList()); + //复制和处理 SysUserOnline 对象列表 + Collections.reverse(userOnlineDTOList); + userOnlineDTOList.removeAll(Collections.singleton(null)); + List userOnlineList = BeanUtil.copyToList(userOnlineDTOList, SysUserOnline.class); + return TableDataInfo.build(userOnlineList); + } + + /** + * 强退当前在线设备 + * + * @param tokenId token值 + */ + @Log(title = "在线设备", businessType = BusinessType.FORCE) + @PostMapping("/{tokenId}") + public R remove(@PathVariable("tokenId") String tokenId) { + try { + // 获取指定账号 id 的 token 集合 + List keys = StpUtil.getTokenValueListByLoginId(StpUtil.getLoginIdAsString()); + keys.stream() + .filter(key -> key.equals(tokenId)) + .findFirst() + .ifPresent(key -> StpUtil.kickoutByTokenValue(tokenId)); + } catch (NotLoginException ignored) { + } + return R.ok(); + } + } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysClientController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysClientController.java index 61d30c76a..13be4a4a9 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysClientController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysClientController.java @@ -97,7 +97,7 @@ public class SysClientController extends BaseController { @Log(title = "客户端管理", businessType = BusinessType.UPDATE) @PutMapping("/changeStatus") public R changeStatus(@RequestBody SysClientBo bo) { - return toAjax(sysClientService.updateUserStatus(bo.getId(), bo.getStatus())); + return toAjax(sysClientService.updateUserStatus(bo.getClientId(), bo.getStatus())); } /** diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java index 130c0d1f3..4f5f23f32 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java @@ -2,6 +2,7 @@ package org.dromara.system.controller.system; import cn.dev33.satoken.annotation.SaCheckPermission; import cn.hutool.core.convert.Convert; +import lombok.RequiredArgsConstructor; import org.dromara.common.core.constant.UserConstants; import org.dromara.common.core.domain.R; import org.dromara.common.core.utils.StringUtils; @@ -11,7 +12,6 @@ import org.dromara.common.web.core.BaseController; import org.dromara.system.domain.bo.SysDeptBo; import org.dromara.system.domain.vo.SysDeptVo; import org.dromara.system.service.ISysDeptService; -import lombok.RequiredArgsConstructor; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -120,4 +120,16 @@ public class SysDeptController extends BaseController { deptService.checkDeptDataScope(deptId); return toAjax(deptService.deleteDeptById(deptId)); } + + /** + * 获取部门选择框列表 + * + * @param deptIds 部门ID串 + */ + @SaCheckPermission("system:dept:query") + @GetMapping("/optionselect") + public R> optionselect(@RequestParam(required = false) Long[] deptIds) { + return R.ok(deptService.selectDeptByIds(deptIds == null ? null : List.of(deptIds))); + } + } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysPostController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysPostController.java index fe62fdbbc..330b3fb52 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysPostController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysPostController.java @@ -1,6 +1,8 @@ package org.dromara.system.controller.system; import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; import org.dromara.common.core.constant.UserConstants; import org.dromara.common.core.domain.R; import org.dromara.common.excel.utils.ExcelUtil; @@ -12,8 +14,6 @@ import org.dromara.common.web.core.BaseController; import org.dromara.system.domain.bo.SysPostBo; import org.dromara.system.domain.vo.SysPostVo; import org.dromara.system.service.ISysPostService; -import jakarta.servlet.http.HttpServletResponse; -import lombok.RequiredArgsConstructor; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -110,12 +110,13 @@ public class SysPostController extends BaseController { /** * 获取岗位选择框列表 + * + * @param postIds 岗位ID串 */ + @SaCheckPermission("system:post:query") @GetMapping("/optionselect") - public R> optionselect() { - SysPostBo postBo = new SysPostBo(); - postBo.setStatus(UserConstants.POST_NORMAL); - List posts = postService.selectPostList(postBo); - return R.ok(posts); + public R> optionselect(@RequestParam(required = false) Long[] postIds) { + return R.ok(postService.selectPostByIds(postIds == null ? null : List.of(postIds))); } + } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java index f9c4b3d31..0cdb67548 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java @@ -19,6 +19,7 @@ import org.dromara.system.domain.vo.ProfileVo; import org.dromara.system.domain.vo.SysOssVo; import org.dromara.system.domain.vo.SysUserVo; import org.dromara.system.service.ISysOssService; +import org.dromara.system.service.ISysRoleService; import org.dromara.system.service.ISysUserService; import lombok.RequiredArgsConstructor; import org.springframework.http.MediaType; @@ -50,8 +51,8 @@ public class SysProfileController extends BaseController { SysUserVo user = userService.selectUserById(LoginHelper.getUserId()); ProfileVo profileVo = new ProfileVo(); profileVo.setUser(user); - profileVo.setRoleGroup(userService.selectUserRoleGroup(user.getUserName())); - profileVo.setPostGroup(userService.selectUserPostGroup(user.getUserName())); + profileVo.setRoleGroup(userService.selectUserRoleGroup(user.getUserId())); + profileVo.setPostGroup(userService.selectUserPostGroup(user.getUserId())); return R.ok(profileVo); } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysRoleController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysRoleController.java index 3a9418b23..d4a9dc8a4 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysRoleController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysRoleController.java @@ -149,11 +149,13 @@ public class SysRoleController extends BaseController { /** * 获取角色选择框列表 + * + * @param roleIds 角色ID串 */ @SaCheckPermission("system:role:query") @GetMapping("/optionselect") - public R> optionselect() { - return R.ok(roleService.selectRoleAll()); + public R> optionselect(@RequestParam(required = false) Long[] roleIds) { + return R.ok(roleService.selectRoleByIds(roleIds == null ? null : List.of(roleIds))); } /** diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java index beefe4a81..b1502ac92 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java @@ -11,7 +11,6 @@ import lombok.RequiredArgsConstructor; import org.dromara.common.core.constant.UserConstants; import org.dromara.common.core.domain.R; import org.dromara.common.core.domain.model.LoginUser; -import org.dromara.common.core.utils.MapstructUtils; import org.dromara.common.core.utils.StreamUtils; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.encrypt.annotation.ApiEncrypt; @@ -72,9 +71,8 @@ public class SysUserController extends BaseController { @SaCheckPermission("system:user:export") @PostMapping("/export") public void export(SysUserBo user, HttpServletResponse response) { - List list = userService.selectUserList(user); - List listVo = MapstructUtils.convert(list, SysUserExportVo.class); - ExcelUtil.exportExcel(listVo, "用户数据", SysUserExportVo.class, response); + List list = userService.selectUserExportList(user); + ExcelUtil.exportExcel(list, "用户数据", SysUserExportVo.class, response); } /** @@ -142,7 +140,7 @@ public class SysUserController extends BaseController { if (ObjectUtil.isNotNull(userId)) { SysUserVo sysUser = userService.selectUserById(userId); userInfoVo.setUser(sysUser); - userInfoVo.setRoleIds(StreamUtils.toList(sysUser.getRoles(), SysRoleVo::getRoleId)); + userInfoVo.setRoleIds(roleService.selectRoleListByUserId(userId)); userInfoVo.setPostIds(postService.selectPostListByUserId(userId)); } return R.ok(userInfoVo); @@ -207,6 +205,19 @@ public class SysUserController extends BaseController { return toAjax(userService.deleteUserByIds(userIds)); } + /** + * 根据用户ID串批量获取用户基础信息 + * + * @param userIds 用户ID串 + * @param deptId 部门ID + */ + @SaCheckPermission("system:user:query") + @GetMapping("/optionselect") + public R> optionselect(@RequestParam(required = false) Long[] userIds, + @RequestParam(required = false) Long deptId) { + return R.ok(userService.selectUserByIds(userIds == null ? null : List.of(userIds), deptId)); + } + /** * 重置密码 */ @@ -241,8 +252,9 @@ public class SysUserController extends BaseController { @SaCheckPermission("system:user:query") @GetMapping("/authRole/{userId}") public R authRole(@PathVariable Long userId) { + userService.checkUserDataScope(userId); SysUserVo user = userService.selectUserById(userId); - List roles = roleService.selectRolesByUserId(userId); + List roles = roleService.selectRolesAuthByUserId(userId); SysUserInfoVo userInfoVo = new SysUserInfoVo(); userInfoVo.setUser(user); userInfoVo.setRoles(LoginHelper.isSuperAdmin(userId) ? roles : StreamUtils.filter(roles, r -> !r.isSuperAdmin())); diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserOnline.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserOnline.java index 6def906e1..ba30eb609 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserOnline.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserOnline.java @@ -7,7 +7,6 @@ import lombok.Data; * * @author Lion Li */ - @Data public class SysUserOnline { diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictTypeBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictTypeBo.java index 39257f70b..fcc1ac11d 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictTypeBo.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictTypeBo.java @@ -6,6 +6,7 @@ import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Size; import lombok.Data; import lombok.EqualsAndHashCode; +import org.dromara.common.core.constant.RegexConstants; import org.dromara.common.mybatis.core.domain.BaseEntity; import org.dromara.system.domain.SysDictType; @@ -37,7 +38,7 @@ public class SysDictTypeBo extends BaseEntity { */ @NotBlank(message = "字典类型不能为空") @Size(min = 0, max = 100, message = "字典类型类型长度不能超过{max}个字符") - @Pattern(regexp = "^[a-z][a-z0-9_]*$", message = "字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)") + @Pattern(regexp = RegexConstants.DICTIONARY_TYPE, message = "字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)") private String dictType; /** diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMenuBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMenuBo.java index 498280a90..fbaafaa63 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMenuBo.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMenuBo.java @@ -4,9 +4,11 @@ import com.fasterxml.jackson.annotation.JsonInclude; import io.github.linpeilie.annotations.AutoMapper; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Size; import lombok.Data; import lombok.EqualsAndHashCode; +import org.dromara.common.core.constant.RegexConstants; import org.dromara.common.mybatis.core.domain.BaseEntity; import org.dromara.system.domain.SysMenu; @@ -92,6 +94,7 @@ public class SysMenuBo extends BaseEntity { */ @JsonInclude(JsonInclude.Include.NON_NULL) @Size(min = 0, max = 100, message = "权限标识长度不能超过{max}个字符") + @Pattern(regexp = RegexConstants.PERMISSION_STRING, message = "权限标识必须符合 tool:build:list 格式") private String perms; /** @@ -104,5 +107,4 @@ public class SysMenuBo extends BaseEntity { */ private String remark; - } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserExportVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserExportVo.java index 3cc5186c8..37ec6b709 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserExportVo.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserExportVo.java @@ -20,7 +20,6 @@ import java.util.Date; @Data @NoArgsConstructor -@AutoMapper(target = SysUserVo.class, convertGenerate = false) public class SysUserExportVo implements Serializable { @Serial @@ -85,14 +84,12 @@ public class SysUserExportVo implements Serializable { /** * 部门名称 */ - @ReverseAutoMapping(target = "deptName", source = "dept.deptName") @ExcelProperty(value = "部门名称") private String deptName; /** * 负责人 */ - @ReverseAutoMapping(target = "leaderName", source = "dept.leaderName") @ExcelProperty(value = "部门负责人") private String leaderName; diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java index 7db91d180..d1f405919 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java @@ -114,9 +114,10 @@ public class SysUserVo implements Serializable { private Date createTime; /** - * 部门对象 + * 部门名 */ - private SysDeptVo dept; + @Translation(type = TransConstant.DEPT_ID_TO_NAME, mapper = "deptId") + private String deptName; /** * 角色对象 diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java index 45ad77e9c..08dda662c 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java @@ -32,7 +32,7 @@ public interface SysDeptMapper extends BaseMapperPlus { @DataPermission({ @DataColumn(key = "deptName", value = "dept_id") }) - SysDeptVo selectDeptById(Long deptId); + long countDeptById(Long deptId); /** * 根据角色ID查询部门树信息 diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysPostMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysPostMapper.java index 48e6a121f..d6d27596f 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysPostMapper.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysPostMapper.java @@ -13,20 +13,12 @@ import java.util.List; */ public interface SysPostMapper extends BaseMapperPlus { - /** - * 根据用户ID获取岗位选择框列表 - * - * @param userId 用户ID - * @return 选中岗位ID列表 - */ - List selectPostListByUserId(Long userId); - /** * 查询用户所属岗位组 * - * @param userName 用户名 + * @param userId 用户ID * @return 结果 */ - List selectPostsByUserName(String userName); + List selectPostsByUserId(Long userId); } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMapper.java index 55ca76976..ac5a47e54 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMapper.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMapper.java @@ -3,12 +3,12 @@ package org.dromara.system.mapper; import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.toolkit.Constants; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Param; import org.dromara.common.mybatis.annotation.DataColumn; import org.dromara.common.mybatis.annotation.DataPermission; import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; import org.dromara.system.domain.SysRole; import org.dromara.system.domain.vo.SysRoleVo; -import org.apache.ibatis.annotations.Param; import java.util.List; @@ -51,21 +51,12 @@ public interface SysRoleMapper extends BaseMapperPlus { */ List selectRolePermissionByUserId(Long userId); - - /** - * 根据用户ID获取角色选择框列表 - * - * @param userId 用户ID - * @return 选中角色ID列表 - */ - List selectRoleListByUserId(Long userId); - /** * 根据用户ID查询角色 * - * @param userName 用户名 + * @param userId 用户ID * @return 角色列表 */ - List selectRolesByUserName(String userName); + List selectRolesByUserId(Long userId); } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java index 43222253c..fc7fc6e16 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java @@ -8,6 +8,7 @@ import org.dromara.common.mybatis.annotation.DataColumn; import org.dromara.common.mybatis.annotation.DataPermission; import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.vo.SysUserExportVo; import org.dromara.system.domain.vo.SysUserVo; import java.util.List; @@ -20,11 +21,17 @@ import java.util.List; public interface SysUserMapper extends BaseMapperPlus { @DataPermission({ - @DataColumn(key = "deptName", value = "d.dept_id"), + @DataColumn(key = "deptName", value = "u.dept_id"), @DataColumn(key = "userName", value = "u.user_id") }) Page selectPageUserList(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "user_id") + }) + List selectUserList(@Param(Constants.WRAPPER) Wrapper queryWrapper); + /** * 根据条件分页查询用户列表 * @@ -35,7 +42,7 @@ public interface SysUserMapper extends BaseMapperPlus { @DataColumn(key = "deptName", value = "d.dept_id"), @DataColumn(key = "userName", value = "u.user_id") }) - List selectUserList(@Param(Constants.WRAPPER) Wrapper queryWrapper); + List selectUserExportList(@Param(Constants.WRAPPER) Wrapper queryWrapper); /** * 根据条件分页查询已配用户角色列表 @@ -61,41 +68,11 @@ public interface SysUserMapper extends BaseMapperPlus { }) Page selectUnallocatedList(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); - /** - * 通过用户名查询用户 - * - * @param userName 用户名 - * @return 用户对象信息 - */ - SysUserVo selectUserByUserName(String userName); - - /** - * 通过手机号查询用户 - * - * @param phonenumber 手机号 - * @return 用户对象信息 - */ - SysUserVo selectUserByPhonenumber(String phonenumber); - - /** - * 通过邮箱查询用户 - * - * @param email 邮箱 - * @return 用户对象信息 - */ - SysUserVo selectUserByEmail(String email); - - /** - * 通过用户ID查询用户 - * - * @param userId 用户ID - * @return 用户对象信息 - */ @DataPermission({ - @DataColumn(key = "deptName", value = "d.dept_id"), - @DataColumn(key = "userName", value = "u.user_id") + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "user_id") }) - SysUserVo selectUserById(Long userId); + long countUserById(Long userId); @Override @DataPermission({ diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysClientService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysClientService.java index db48d4b79..d0f8a3cbe 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysClientService.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysClientService.java @@ -25,7 +25,7 @@ public interface ISysClientService { /** * 查询客户端信息基于客户端id */ - SysClient queryByClientId(String clientId); + SysClientVo queryByClientId(String clientId); /** * 查询客户端管理列表 @@ -50,7 +50,7 @@ public interface ISysClientService { /** * 修改状态 */ - int updateUserStatus(Long id, String status); + int updateUserStatus(String clientId, String status); /** * 校验并批量删除客户端管理信息 diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDeptService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDeptService.java index b20938187..bf16642fe 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDeptService.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDeptService.java @@ -52,6 +52,14 @@ public interface ISysDeptService { */ SysDeptVo selectDeptById(Long deptId); + /** + * 通过部门ID串查询部门 + * + * @param deptIds 部门id串 + * @return 部门列表信息 + */ + List selectDeptByIds(List deptIds); + /** * 根据ID查询所有子部门数(正常状态) * diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssConfigService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssConfigService.java index a8bc57b9c..2f6dfc9a1 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssConfigService.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssConfigService.java @@ -31,12 +31,11 @@ public interface ISysOssConfigService { */ TableDataInfo queryPageList(SysOssConfigBo bo, PageQuery pageQuery); - /** * 根据新增业务对象插入对象存储配置 * * @param bo 对象存储配置新增业务对象 - * @return + * @return 结果 */ Boolean insertByBo(SysOssConfigBo bo); @@ -44,7 +43,7 @@ public interface ISysOssConfigService { * 根据编辑业务对象修改对象存储配置 * * @param bo 对象存储配置编辑业务对象 - * @return + * @return 结果 */ Boolean updateByBo(SysOssConfigBo bo); @@ -53,7 +52,7 @@ public interface ISysOssConfigService { * * @param ids 主键集合 * @param isValid 是否校验,true-删除前校验,false-不校验 - * @return + * @return 结果 */ Boolean deleteWithValidByIds(Collection ids, Boolean isValid); diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssService.java index 2dfe01fe9..057c068ce 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssService.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssService.java @@ -19,18 +19,62 @@ import java.util.List; */ public interface ISysOssService { + /** + * 查询OSS对象存储列表 + * + * @param sysOss OSS对象存储分页查询对象 + * @param pageQuery 分页查询实体类 + * @return 结果 + */ TableDataInfo queryPageList(SysOssBo sysOss, PageQuery pageQuery); + /** + * 根据一组 ossIds 获取对应的 SysOssVo 列表 + * + * @param ossIds 一组文件在数据库中的唯一标识集合 + * @return 包含 SysOssVo 对象的列表 + */ List listByIds(Collection ossIds); + /** + * 根据 ossId 从缓存或数据库中获取 SysOssVo 对象 + * + * @param ossId 文件在数据库中的唯一标识 + * @return SysOssVo 对象,包含文件信息 + */ SysOssVo getById(Long ossId); + /** + * 上传 MultipartFile 到对象存储服务,并保存文件信息到数据库 + * + * @param file 要上传的 MultipartFile 对象 + * @return 上传成功后的 SysOssVo 对象,包含文件信息 + */ SysOssVo upload(MultipartFile file); + /** + * 上传文件到对象存储服务,并保存文件信息到数据库 + * + * @param file 要上传的文件对象 + * @return 上传成功后的 SysOssVo 对象,包含文件信息 + */ SysOssVo upload(File file); + /** + * 文件下载方法,支持一次性下载完整文件 + * + * @param ossId OSS对象ID + * @param response HttpServletResponse对象,用于设置响应头和向客户端发送文件内容 + */ void download(Long ossId, HttpServletResponse response) throws IOException; + /** + * 删除OSS对象存储 + * + * @param ids OSS对象ID串 + * @param isValid 判断是否需要校验 + * @return 结果 + */ Boolean deleteWithValidByIds(Collection ids, Boolean isValid); } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java index c6409c862..c43f0395c 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java @@ -48,6 +48,14 @@ public interface ISysPostService { */ List selectPostListByUserId(Long userId); + /** + * 通过岗位ID串查询岗位 + * + * @param postIds 岗位id串 + * @return 岗位列表信息 + */ + List selectPostByIds(List postIds); + /** * 校验岗位名称 * diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysRoleService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysRoleService.java index d2ee61f8a..64740aeff 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysRoleService.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysRoleService.java @@ -35,6 +35,14 @@ public interface ISysRoleService { */ List selectRolesByUserId(Long userId); + /** + * 根据用户ID查询角色列表(包含被授权状态) + * + * @param userId 用户ID + * @return 角色列表 + */ + List selectRolesAuthByUserId(Long userId); + /** * 根据用户ID查询角色权限 * @@ -66,6 +74,14 @@ public interface ISysRoleService { */ SysRoleVo selectRoleById(Long roleId); + /** + * 通过角色ID串查询角色 + * + * @param roleIds 角色ID串 + * @return 角色列表信息 + */ + List selectRoleByIds(List roleIds); + /** * 校验角色名称是否唯一 * @@ -180,4 +196,5 @@ public interface ISysRoleService { int insertAuthUsers(Long roleId, Long[] userIds); void cleanOnlineUserByRole(Long roleId); + } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java index bbe78be2b..0325a2558 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java @@ -3,6 +3,7 @@ package org.dromara.system.service; import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.system.domain.bo.SysUserBo; +import org.dromara.system.domain.vo.SysUserExportVo; import org.dromara.system.domain.vo.SysUserVo; import java.util.List; @@ -23,7 +24,7 @@ public interface ISysUserService { * @param user 用户信息 * @return 用户信息集合信息 */ - List selectUserList(SysUserBo user); + List selectUserExportList(SysUserBo user); /** * 根据条件分页查询已分配用户角色列表 @@ -65,21 +66,30 @@ public interface ISysUserService { */ SysUserVo selectUserById(Long userId); + /** + * 通过用户ID串查询用户 + * + * @param userIds 用户ID串 + * @param deptId 部门id + * @return 用户列表信息 + */ + List selectUserByIds(List userIds, Long deptId); + /** * 根据用户ID查询用户所属角色组 * - * @param userName 用户名 + * @param userId 用户ID * @return 结果 */ - String selectUserRoleGroup(String userName); + String selectUserRoleGroup(Long userId); /** * 根据用户ID查询用户所属岗位组 * - * @param userName 用户名 + * @param userId 用户ID * @return 结果 */ - String selectUserPostGroup(String userName); + String selectUserPostGroup(Long userId); /** * 校验用户名称是否唯一 @@ -205,8 +215,8 @@ public interface ISysUserService { /** * 通过部门id查询当前部门所有用户 * - * @param deptId - * @return + * @param deptId 部门id + * @return 结果 */ List selectUserListByDept(Long deptId); } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java index aecaf668c..26bc49157 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java @@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.CacheNames; import org.dromara.common.core.utils.MapstructUtils; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.mybatis.core.page.PageQuery; @@ -16,6 +17,8 @@ import org.dromara.system.domain.bo.SysClientBo; import org.dromara.system.domain.vo.SysClientVo; import org.dromara.system.mapper.SysClientMapper; import org.dromara.system.service.ISysClientService; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import java.util.Collection; @@ -48,9 +51,10 @@ public class SysClientServiceImpl implements ISysClientService { /** * 查询客户端管理 */ + @Cacheable(cacheNames = CacheNames.SYS_CLIENT, key = "#clientId") @Override - public SysClient queryByClientId(String clientId) { - return baseMapper.selectOne(new LambdaQueryWrapper().eq(SysClient::getClientId, clientId)); + public SysClientVo queryByClientId(String clientId) { + return baseMapper.selectVoOne(new LambdaQueryWrapper().eq(SysClient::getClientId, clientId)); } /** @@ -105,6 +109,7 @@ public class SysClientServiceImpl implements ISysClientService { /** * 修改客户端管理 */ + @CacheEvict(cacheNames = CacheNames.SYS_CLIENT, key = "#bo.clientId") @Override public Boolean updateByBo(SysClientBo bo) { SysClient update = MapstructUtils.convert(bo, SysClient.class); @@ -116,12 +121,13 @@ public class SysClientServiceImpl implements ISysClientService { /** * 修改状态 */ + @CacheEvict(cacheNames = CacheNames.SYS_CLIENT, key = "#clientId") @Override - public int updateUserStatus(Long id, String status) { + public int updateUserStatus(String clientId, String status) { return baseMapper.update(null, new LambdaUpdateWrapper() .set(SysClient::getStatus, status) - .eq(SysClient::getId, id)); + .eq(SysClient::getClientId, clientId)); } /** @@ -134,6 +140,7 @@ public class SysClientServiceImpl implements ISysClientService { /** * 批量删除客户端管理 */ + @CacheEvict(cacheNames = CacheNames.SYS_CLIENT, allEntries = true) @Override public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { if (isValid) { diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java index fe5cc0e54..86edf59d4 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java @@ -7,6 +7,7 @@ import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; import org.dromara.common.core.constant.CacheNames; import org.dromara.common.core.constant.UserConstants; import org.dromara.common.core.exception.ServiceException; @@ -27,7 +28,6 @@ import org.dromara.system.mapper.SysDeptMapper; import org.dromara.system.mapper.SysRoleMapper; import org.dromara.system.mapper.SysUserMapper; import org.dromara.system.service.ISysDeptService; -import lombok.RequiredArgsConstructor; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; @@ -83,6 +83,7 @@ public class SysDeptServiceImpl implements ISysDeptService, DeptService { lqw.eq(ObjectUtil.isNotNull(bo.getParentId()), SysDept::getParentId, bo.getParentId()); lqw.like(StringUtils.isNotBlank(bo.getDeptName()), SysDept::getDeptName, bo.getDeptName()); lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysDept::getStatus, bo.getStatus()); + lqw.orderByAsc(SysDept::getAncestors); lqw.orderByAsc(SysDept::getParentId); lqw.orderByAsc(SysDept::getOrderNum); lqw.orderByAsc(SysDept::getDeptId); @@ -138,6 +139,14 @@ public class SysDeptServiceImpl implements ISysDeptService, DeptService { return dept; } + @Override + public List selectDeptByIds(List deptIds) { + return baseMapper.selectDeptList(new LambdaQueryWrapper() + .select(SysDept::getDeptId, SysDept::getDeptName, SysDept::getLeader) + .eq(SysDept::getStatus, UserConstants.DEPT_NORMAL) + .in(CollUtil.isNotEmpty(deptIds), SysDept::getDeptId, deptIds)); + } + /** * 通过部门ID查询部门名称 * @@ -221,8 +230,7 @@ public class SysDeptServiceImpl implements ISysDeptService, DeptService { if (LoginHelper.isSuperAdmin()) { return; } - SysDeptVo dept = baseMapper.selectDeptById(deptId); - if (ObjectUtil.isNull(dept)) { + if (baseMapper.countDeptById(deptId) == 0) { throw new ServiceException("没有权限访问部门数据!"); } } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java index 346d6bc83..bc6663f0c 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java @@ -1,13 +1,12 @@ package org.dromara.system.service.impl; -import cn.dev33.satoken.context.SaHolder; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import org.dromara.common.core.constant.CacheConstants; +import lombok.RequiredArgsConstructor; import org.dromara.common.core.constant.CacheNames; import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.service.DictService; @@ -26,7 +25,6 @@ import org.dromara.system.domain.vo.SysDictTypeVo; import org.dromara.system.mapper.SysDictDataMapper; import org.dromara.system.mapper.SysDictTypeMapper; import org.dromara.system.service.ISysDictTypeService; -import lombok.RequiredArgsConstructor; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; @@ -217,16 +215,9 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService, DictService * @param separator 分隔符 * @return 字典标签 */ - @SuppressWarnings("unchecked cast") @Override public String getDictLabel(String dictType, String dictValue, String separator) { - // 优先从本地缓存获取 - List datas = (List) SaHolder.getStorage().get(CacheConstants.SYS_DICT_KEY + dictType); - if (ObjectUtil.isNull(datas)) { - datas = SpringUtils.getAopProxy(this).selectDictDataByType(dictType); - SaHolder.getStorage().set(CacheConstants.SYS_DICT_KEY + dictType, datas); - } - + List datas = SpringUtils.getAopProxy(this).selectDictDataByType(dictType); Map map = StreamUtils.toMap(datas, SysDictDataVo::getDictValue, SysDictDataVo::getDictLabel); if (StringUtils.containsAny(dictValue, separator)) { return Arrays.stream(dictValue.split(separator)) @@ -245,16 +236,9 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService, DictService * @param separator 分隔符 * @return 字典值 */ - @SuppressWarnings("unchecked cast") @Override public String getDictValue(String dictType, String dictLabel, String separator) { - // 优先从本地缓存获取 - List datas = (List) SaHolder.getStorage().get(CacheConstants.SYS_DICT_KEY + dictType); - if (ObjectUtil.isNull(datas)) { - datas = SpringUtils.getAopProxy(this).selectDictDataByType(dictType); - SaHolder.getStorage().set(CacheConstants.SYS_DICT_KEY + dictType, datas); - } - + List datas = SpringUtils.getAopProxy(this).selectDictDataByType(dictType); Map map = StreamUtils.toMap(datas, SysDictDataVo::getDictLabel, SysDictDataVo::getDictValue); if (StringUtils.containsAny(dictLabel, separator)) { return Arrays.stream(dictLabel.split(separator)) diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java index d215d5951..9c930a0c5 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java @@ -5,30 +5,29 @@ import cn.hutool.http.useragent.UserAgent; import cn.hutool.http.useragent.UserAgentUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.dromara.common.core.constant.Constants; import org.dromara.common.core.utils.MapstructUtils; -import org.dromara.common.mybatis.core.page.PageQuery; -import org.dromara.common.log.event.LogininforEvent; -import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.core.utils.ServletUtils; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.ip.AddressUtils; +import org.dromara.common.log.event.LogininforEvent; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.satoken.utils.LoginHelper; -import org.dromara.system.domain.SysClient; import org.dromara.system.domain.SysLogininfor; import org.dromara.system.domain.bo.SysLogininforBo; +import org.dromara.system.domain.vo.SysClientVo; import org.dromara.system.domain.vo.SysLogininforVo; -import org.dromara.system.mapper.SysClientMapper; import org.dromara.system.mapper.SysLogininforMapper; import org.dromara.system.service.ISysClientService; import org.dromara.system.service.ISysLogininforService; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; -import jakarta.servlet.http.HttpServletRequest; import java.util.Arrays; import java.util.Date; import java.util.List; @@ -60,10 +59,10 @@ public class SysLogininforServiceImpl implements ISysLogininforService { final UserAgent userAgent = UserAgentUtil.parse(request.getHeader("User-Agent")); final String ip = ServletUtils.getClientIP(request); // 客户端信息 - String clientid = request.getHeader(LoginHelper.CLIENT_KEY); - SysClient client = null; - if (StringUtils.isNotBlank(clientid)) { - client = clientService.queryByClientId(clientid); + String clientId = request.getHeader(LoginHelper.CLIENT_KEY); + SysClientVo client = null; + if (StringUtils.isNotBlank(clientId)) { + client = clientService.queryByClientId(clientId); } String address = AddressUtils.getRealAddressByIP(ip); diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysNoticeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysNoticeServiceImpl.java index 8e2b5ac4a..18b7a08da 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysNoticeServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysNoticeServiceImpl.java @@ -9,6 +9,7 @@ import org.dromara.common.core.utils.StringUtils; import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.system.domain.SysNotice; +import org.dromara.system.domain.SysUser; import org.dromara.system.domain.bo.SysNoticeBo; import org.dromara.system.domain.vo.SysNoticeVo; import org.dromara.system.domain.vo.SysUserVo; @@ -68,7 +69,7 @@ public class SysNoticeServiceImpl implements ISysNoticeService { lqw.like(StringUtils.isNotBlank(bo.getNoticeTitle()), SysNotice::getNoticeTitle, bo.getNoticeTitle()); lqw.eq(StringUtils.isNotBlank(bo.getNoticeType()), SysNotice::getNoticeType, bo.getNoticeType()); if (StringUtils.isNotBlank(bo.getCreateByName())) { - SysUserVo sysUser = userMapper.selectUserByUserName(bo.getCreateByName()); + SysUserVo sysUser = userMapper.selectVoOne(new LambdaQueryWrapper().eq(SysUser::getUserName, bo.getCreateByName())); lqw.eq(SysNotice::getCreateBy, ObjectUtil.isNotNull(sysUser) ? sysUser.getUserId() : null); } lqw.orderByAsc(SysNotice::getNoticeId); diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java index c7d47191d..1df221c32 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java @@ -6,6 +6,8 @@ import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; import org.dromara.common.core.constant.CacheNames; import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.service.OssService; @@ -25,8 +27,6 @@ import org.dromara.system.domain.bo.SysOssBo; import org.dromara.system.domain.vo.SysOssVo; import org.dromara.system.mapper.SysOssMapper; import org.dromara.system.service.ISysOssService; -import jakarta.servlet.http.HttpServletResponse; -import lombok.RequiredArgsConstructor; import org.jetbrains.annotations.NotNull; import org.springframework.cache.annotation.Cacheable; import org.springframework.http.MediaType; @@ -36,7 +36,10 @@ import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; /** * 文件上传 服务层实现 @@ -49,6 +52,13 @@ public class SysOssServiceImpl implements ISysOssService, OssService { private final SysOssMapper baseMapper; + /** + * 查询OSS对象存储列表 + * + * @param bo OSS对象存储分页查询对象 + * @param pageQuery 分页查询实体类 + * @return 结果 + */ @Override public TableDataInfo queryPageList(SysOssBo bo, PageQuery pageQuery) { LambdaQueryWrapper lqw = buildQueryWrapper(bo); @@ -58,6 +68,12 @@ public class SysOssServiceImpl implements ISysOssService, OssService { return TableDataInfo.build(result); } + /** + * 根据一组 ossIds 获取对应的 SysOssVo 列表 + * + * @param ossIds 一组文件在数据库中的唯一标识集合 + * @return 包含 SysOssVo 对象的列表 + */ @Override public List listByIds(Collection ossIds) { List list = new ArrayList<>(); @@ -75,6 +91,12 @@ public class SysOssServiceImpl implements ISysOssService, OssService { return list; } + /** + * 根据一组 ossIds 获取对应文件的 URL 列表 + * + * @param ossIds 以逗号分隔的 ossId 字符串 + * @return 以逗号分隔的文件 URL 字符串 + */ @Override public String selectUrlByIds(String ossIds) { List list = new ArrayList<>(); @@ -107,12 +129,25 @@ public class SysOssServiceImpl implements ISysOssService, OssService { return lqw; } + /** + * 根据 ossId 从缓存或数据库中获取 SysOssVo 对象 + * + * @param ossId 文件在数据库中的唯一标识 + * @return SysOssVo 对象,包含文件信息 + */ @Cacheable(cacheNames = CacheNames.SYS_OSS, key = "#ossId") @Override public SysOssVo getById(Long ossId) { return baseMapper.selectVoById(ossId); } + + /** + * 文件下载方法,支持一次性下载完整文件 + * + * @param ossId OSS对象ID + * @param response HttpServletResponse对象,用于设置响应头和向客户端发送文件内容 + */ @Override public void download(Long ossId, HttpServletResponse response) throws IOException { SysOssVo sysOss = SpringUtils.getAopProxy(this).getById(ossId); @@ -122,7 +157,7 @@ public class SysOssServiceImpl implements ISysOssService, OssService { FileUtils.setAttachmentResponseHeader(response, sysOss.getOriginalName()); response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8"); OssClient storage = OssFactory.instance(sysOss.getService()); - try(InputStream inputStream = storage.getObjectContent(sysOss.getUrl())) { + try (InputStream inputStream = storage.getObjectContent(sysOss.getUrl())) { int available = inputStream.available(); IoUtil.copy(inputStream, response.getOutputStream(), available); response.setContentLength(available); @@ -131,6 +166,13 @@ public class SysOssServiceImpl implements ISysOssService, OssService { } } + /** + * 上传 MultipartFile 到对象存储服务,并保存文件信息到数据库 + * + * @param file 要上传的 MultipartFile 对象 + * @return 上传成功后的 SysOssVo 对象,包含文件信息 + * @throws ServiceException 如果上传过程中发生异常,则抛出 ServiceException 异常 + */ @Override public SysOssVo upload(MultipartFile file) { String originalfileName = file.getOriginalFilename(); @@ -138,7 +180,7 @@ public class SysOssServiceImpl implements ISysOssService, OssService { OssClient storage = OssFactory.instance(); UploadResult uploadResult; try { - uploadResult = storage.uploadSuffix(file.getBytes(), suffix, file.getContentType()); + uploadResult = storage.uploadSuffix(file.getBytes(), suffix); } catch (IOException e) { throw new ServiceException(e.getMessage()); } @@ -146,6 +188,12 @@ public class SysOssServiceImpl implements ISysOssService, OssService { return buildResultEntity(originalfileName, suffix, storage.getConfigKey(), uploadResult); } + /** + * 上传文件到对象存储服务,并保存文件信息到数据库 + * + * @param file 要上传的文件对象 + * @return 上传成功后的 SysOssVo 对象,包含文件信息 + */ @Override public SysOssVo upload(File file) { String originalfileName = file.getName(); @@ -169,6 +217,13 @@ public class SysOssServiceImpl implements ISysOssService, OssService { return this.matchingUrl(sysOssVo); } + /** + * 删除OSS对象存储 + * + * @param ids OSS对象ID串 + * @param isValid 判断是否需要校验 + * @return 结果 + */ @Override public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { if (isValid) { @@ -183,7 +238,7 @@ public class SysOssServiceImpl implements ISysOssService, OssService { } /** - * 匹配Url + * 桶类型为 private 的URL 修改为临时URL时长为120s * * @param oss OSS对象 * @return oss 匹配Url的OSS对象 diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java index b69a06c5f..33b98af59 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java @@ -1,12 +1,16 @@ package org.dromara.system.service.impl; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.UserConstants; import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StreamUtils; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.TableDataInfo; @@ -17,7 +21,6 @@ import org.dromara.system.domain.vo.SysPostVo; import org.dromara.system.mapper.SysPostMapper; import org.dromara.system.mapper.SysUserPostMapper; import org.dromara.system.service.ISysPostService; -import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import java.util.Arrays; @@ -92,7 +95,22 @@ public class SysPostServiceImpl implements ISysPostService { */ @Override public List selectPostListByUserId(Long userId) { - return baseMapper.selectPostListByUserId(userId); + List list = baseMapper.selectPostsByUserId(userId); + return StreamUtils.toList(list, SysPostVo::getPostId); + } + + /** + * 通过岗位ID串查询岗位 + * + * @param postIds 岗位id串 + * @return 岗位列表信息 + */ + @Override + public List selectPostByIds(List postIds) { + return baseMapper.selectVoList(new LambdaQueryWrapper() + .select(SysPost::getPostId, SysPost::getPostName, SysPost::getPostCode) + .eq(SysPost::getStatus, UserConstants.POST_NORMAL) + .in(CollUtil.isNotEmpty(postIds), SysPost::getPostId, postIds)); } /** diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java index 8a2b9390f..abd294f3e 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java @@ -80,7 +80,6 @@ public class SysRoleServiceImpl implements ISysRoleService { .between(params.get("beginTime") != null && params.get("endTime") != null, "r.create_time", params.get("beginTime"), params.get("endTime")) .orderByAsc("r.role_sort").orderByAsc("r.create_time"); - ; return wrapper; } @@ -92,6 +91,17 @@ public class SysRoleServiceImpl implements ISysRoleService { */ @Override public List selectRolesByUserId(Long userId) { + return baseMapper.selectRolesByUserId(userId); + } + + /** + * 根据用户ID查询角色列表(包含被授权状态) + * + * @param userId 用户ID + * @return 角色列表 + */ + @Override + public List selectRolesAuthByUserId(Long userId) { List userRoles = baseMapper.selectRolePermissionByUserId(userId); List roles = selectRoleAll(); for (SysRoleVo role : roles) { @@ -141,7 +151,8 @@ public class SysRoleServiceImpl implements ISysRoleService { */ @Override public List selectRoleListByUserId(Long userId) { - return baseMapper.selectRoleListByUserId(userId); + List list = baseMapper.selectRolesByUserId(userId); + return StreamUtils.toList(list, SysRoleVo::getRoleId); } /** @@ -155,6 +166,19 @@ public class SysRoleServiceImpl implements ISysRoleService { return baseMapper.selectRoleById(roleId); } + /** + * 通过角色ID串查询角色 + * + * @param roleIds 角色ID串 + * @return 角色列表信息 + */ + @Override + public List selectRoleByIds(List roleIds) { + return baseMapper.selectRoleList(new QueryWrapper() + .eq("r.status", UserConstants.ROLE_NORMAL) + .in(CollUtil.isNotEmpty(roleIds), "r.role_id", roleIds)); + } + /** * 校验角色名称是否唯一 * diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java index 7ee19e851..a4d553b49 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java @@ -29,6 +29,7 @@ import org.dromara.system.domain.SysUserRole; import org.dromara.system.domain.bo.SysUserBo; import org.dromara.system.domain.vo.SysPostVo; import org.dromara.system.domain.vo.SysRoleVo; +import org.dromara.system.domain.vo.SysUserExportVo; import org.dromara.system.domain.vo.SysUserVo; import org.dromara.system.mapper.*; import org.dromara.system.service.ISysUserService; @@ -69,28 +70,28 @@ public class SysUserServiceImpl implements ISysUserService, UserService { * @return 用户信息集合信息 */ @Override - public List selectUserList(SysUserBo user) { - return baseMapper.selectUserList(this.buildQueryWrapper(user)); + public List selectUserExportList(SysUserBo user) { + return baseMapper.selectUserExportList(this.buildQueryWrapper(user)); } private Wrapper buildQueryWrapper(SysUserBo user) { Map params = user.getParams(); QueryWrapper wrapper = Wrappers.query(); wrapper.eq("u.del_flag", UserConstants.USER_NORMAL) - .eq(ObjectUtil.isNotNull(user.getUserId()), "u.user_id", user.getUserId()) - .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName()) - .eq(StringUtils.isNotBlank(user.getStatus()), "u.status", user.getStatus()) - .like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber()) - .between(params.get("beginTime") != null && params.get("endTime") != null, - "u.create_time", params.get("beginTime"), params.get("endTime")) - .and(ObjectUtil.isNotNull(user.getDeptId()), w -> { - List deptList = deptMapper.selectList(new LambdaQueryWrapper() - .select(SysDept::getDeptId) - .apply(DataBaseHelper.findInSet(user.getDeptId(), "ancestors"))); - List ids = StreamUtils.toList(deptList, SysDept::getDeptId); - ids.add(user.getDeptId()); - w.in("u.dept_id", ids); - }).orderByAsc("u.user_id"); + .eq(ObjectUtil.isNotNull(user.getUserId()), "u.user_id", user.getUserId()) + .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName()) + .eq(StringUtils.isNotBlank(user.getStatus()), "u.status", user.getStatus()) + .like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber()) + .between(params.get("beginTime") != null && params.get("endTime") != null, + "u.create_time", params.get("beginTime"), params.get("endTime")) + .and(ObjectUtil.isNotNull(user.getDeptId()), w -> { + List deptList = deptMapper.selectList(new LambdaQueryWrapper() + .select(SysDept::getDeptId) + .apply(DataBaseHelper.findInSet(user.getDeptId(), "ancestors"))); + List ids = StreamUtils.toList(deptList, SysDept::getDeptId); + ids.add(user.getDeptId()); + w.in("u.dept_id", ids); + }).orderByAsc("u.user_id"); return wrapper; } @@ -104,11 +105,11 @@ public class SysUserServiceImpl implements ISysUserService, UserService { public TableDataInfo selectAllocatedList(SysUserBo user, PageQuery pageQuery) { QueryWrapper wrapper = Wrappers.query(); wrapper.eq("u.del_flag", UserConstants.USER_NORMAL) - .eq(ObjectUtil.isNotNull(user.getRoleId()), "r.role_id", user.getRoleId()) - .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName()) - .eq(StringUtils.isNotBlank(user.getStatus()), "u.status", user.getStatus()) - .like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber()) - .orderByAsc("u.user_id"); + .eq(ObjectUtil.isNotNull(user.getRoleId()), "r.role_id", user.getRoleId()) + .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName()) + .eq(StringUtils.isNotBlank(user.getStatus()), "u.status", user.getStatus()) + .like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber()) + .orderByAsc("u.user_id"); Page page = baseMapper.selectAllocatedList(pageQuery.build(), wrapper); return TableDataInfo.build(page); } @@ -124,11 +125,11 @@ public class SysUserServiceImpl implements ISysUserService, UserService { List userIds = userRoleMapper.selectUserIdsByRoleId(user.getRoleId()); QueryWrapper wrapper = Wrappers.query(); wrapper.eq("u.del_flag", UserConstants.USER_NORMAL) - .and(w -> w.ne("r.role_id", user.getRoleId()).or().isNull("r.role_id")) - .notIn(CollUtil.isNotEmpty(userIds), "u.user_id", userIds) - .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName()) - .like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber()) - .orderByAsc("u.user_id"); + .and(w -> w.ne("r.role_id", user.getRoleId()).or().isNull("r.role_id")) + .notIn(CollUtil.isNotEmpty(userIds), "u.user_id", userIds) + .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName()) + .like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber()) + .orderByAsc("u.user_id"); Page page = baseMapper.selectUnallocatedList(pageQuery.build(), wrapper); return TableDataInfo.build(page); } @@ -141,7 +142,7 @@ public class SysUserServiceImpl implements ISysUserService, UserService { */ @Override public SysUserVo selectUserByUserName(String userName) { - return baseMapper.selectUserByUserName(userName); + return baseMapper.selectVoOne(new LambdaQueryWrapper().eq(SysUser::getUserName, userName)); } /** @@ -152,7 +153,7 @@ public class SysUserServiceImpl implements ISysUserService, UserService { */ @Override public SysUserVo selectUserByPhonenumber(String phonenumber) { - return baseMapper.selectUserByPhonenumber(phonenumber); + return baseMapper.selectVoOne(new LambdaQueryWrapper().eq(SysUser::getPhonenumber, phonenumber)); } /** @@ -163,18 +164,39 @@ public class SysUserServiceImpl implements ISysUserService, UserService { */ @Override public SysUserVo selectUserById(Long userId) { - return baseMapper.selectUserById(userId); + SysUserVo user = baseMapper.selectVoById(userId); + if (ObjectUtil.isNull(user)) { + return user; + } + user.setRoles(roleMapper.selectRolesByUserId(user.getUserId())); + return user; + } + + /** + * 通过用户ID串查询用户 + * + * @param userIds 用户ID串 + * @param deptId 部门id + * @return 用户列表信息 + */ + @Override + public List selectUserByIds(List userIds, Long deptId) { + return baseMapper.selectUserList(new LambdaQueryWrapper() + .select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName) + .eq(SysUser::getStatus, UserConstants.USER_NORMAL) + .eq(ObjectUtil.isNotNull(deptId), SysUser::getDeptId, deptId) + .in(CollUtil.isNotEmpty(userIds), SysUser::getUserId, userIds)); } /** * 查询用户所属角色组 * - * @param userName 用户名 + * @param userId 用户ID * @return 结果 */ @Override - public String selectUserRoleGroup(String userName) { - List list = roleMapper.selectRolesByUserName(userName); + public String selectUserRoleGroup(Long userId) { + List list = roleMapper.selectRolesByUserId(userId); if (CollUtil.isEmpty(list)) { return StringUtils.EMPTY; } @@ -184,12 +206,12 @@ public class SysUserServiceImpl implements ISysUserService, UserService { /** * 查询用户所属岗位组 * - * @param userName 用户名 + * @param userId 用户ID * @return 结果 */ @Override - public String selectUserPostGroup(String userName) { - List list = postMapper.selectPostsByUserName(userName); + public String selectUserPostGroup(Long userId) { + List list = postMapper.selectPostsByUserId(userId); if (CollUtil.isEmpty(list)) { return StringUtils.EMPTY; } @@ -205,8 +227,8 @@ public class SysUserServiceImpl implements ISysUserService, UserService { @Override public boolean checkUserNameUnique(SysUserBo user) { boolean exist = baseMapper.exists(new LambdaQueryWrapper() - .eq(SysUser::getUserName, user.getUserName()) - .ne(ObjectUtil.isNotNull(user.getUserId()), SysUser::getUserId, user.getUserId())); + .eq(SysUser::getUserName, user.getUserName()) + .ne(ObjectUtil.isNotNull(user.getUserId()), SysUser::getUserId, user.getUserId())); return !exist; } @@ -218,8 +240,8 @@ public class SysUserServiceImpl implements ISysUserService, UserService { @Override public boolean checkPhoneUnique(SysUserBo user) { boolean exist = baseMapper.exists(new LambdaQueryWrapper() - .eq(SysUser::getPhonenumber, user.getPhonenumber()) - .ne(ObjectUtil.isNotNull(user.getUserId()), SysUser::getUserId, user.getUserId())); + .eq(SysUser::getPhonenumber, user.getPhonenumber()) + .ne(ObjectUtil.isNotNull(user.getUserId()), SysUser::getUserId, user.getUserId())); return !exist; } @@ -231,8 +253,8 @@ public class SysUserServiceImpl implements ISysUserService, UserService { @Override public boolean checkEmailUnique(SysUserBo user) { boolean exist = baseMapper.exists(new LambdaQueryWrapper() - .eq(SysUser::getEmail, user.getEmail()) - .ne(ObjectUtil.isNotNull(user.getUserId()), SysUser::getUserId, user.getUserId())); + .eq(SysUser::getEmail, user.getEmail()) + .ne(ObjectUtil.isNotNull(user.getUserId()), SysUser::getUserId, user.getUserId())); return !exist; } @@ -261,7 +283,7 @@ public class SysUserServiceImpl implements ISysUserService, UserService { if (LoginHelper.isSuperAdmin()) { return; } - if (ObjectUtil.isNull(baseMapper.selectUserById(userId))) { + if (baseMapper.countUserById(userId) == 0) { throw new ServiceException("没有权限访问用户数据!"); } } @@ -345,9 +367,9 @@ public class SysUserServiceImpl implements ISysUserService, UserService { @Override public int updateUserStatus(Long userId, String status) { return baseMapper.update(null, - new LambdaUpdateWrapper() - .set(SysUser::getStatus, status) - .eq(SysUser::getUserId, userId)); + new LambdaUpdateWrapper() + .set(SysUser::getStatus, status) + .eq(SysUser::getUserId, userId)); } /** @@ -359,12 +381,12 @@ public class SysUserServiceImpl implements ISysUserService, UserService { @Override public int updateUserProfile(SysUserBo user) { return baseMapper.update(null, - new LambdaUpdateWrapper() - .set(ObjectUtil.isNotNull(user.getNickName()), SysUser::getNickName, user.getNickName()) - .set(SysUser::getPhonenumber, user.getPhonenumber()) - .set(SysUser::getEmail, user.getEmail()) - .set(SysUser::getSex, user.getSex()) - .eq(SysUser::getUserId, user.getUserId())); + new LambdaUpdateWrapper() + .set(ObjectUtil.isNotNull(user.getNickName()), SysUser::getNickName, user.getNickName()) + .set(SysUser::getPhonenumber, user.getPhonenumber()) + .set(SysUser::getEmail, user.getEmail()) + .set(SysUser::getSex, user.getSex()) + .eq(SysUser::getUserId, user.getUserId())); } /** @@ -377,9 +399,9 @@ public class SysUserServiceImpl implements ISysUserService, UserService { @Override public boolean updateUserAvatar(Long userId, Long avatar) { return baseMapper.update(null, - new LambdaUpdateWrapper() - .set(SysUser::getAvatar, avatar) - .eq(SysUser::getUserId, userId)) > 0; + new LambdaUpdateWrapper() + .set(SysUser::getAvatar, avatar) + .eq(SysUser::getUserId, userId)) > 0; } /** @@ -392,9 +414,9 @@ public class SysUserServiceImpl implements ISysUserService, UserService { @Override public int resetUserPwd(Long userId, String password) { return baseMapper.update(null, - new LambdaUpdateWrapper() - .set(SysUser::getPassword, password) - .eq(SysUser::getUserId, userId)); + new LambdaUpdateWrapper() + .set(SysUser::getPassword, password) + .eq(SysUser::getUserId, userId)); } /** @@ -518,8 +540,8 @@ public class SysUserServiceImpl implements ISysUserService, UserService { /** * 通过部门id查询当前部门所有用户 * - * @param deptId - * @return + * @param deptId 部门ID + * @return 用户信息集合信息 */ @Override public List selectUserListByDept(Long deptId) { @@ -529,14 +551,26 @@ public class SysUserServiceImpl implements ISysUserService, UserService { return baseMapper.selectVoList(lqw); } + /** + * 通过用户ID查询用户账户 + * + * @param userId 用户ID + * @return 用户账户 + */ @Cacheable(cacheNames = CacheNames.SYS_USER_NAME, key = "#userId") @Override public String selectUserNameById(Long userId) { SysUser sysUser = baseMapper.selectOne(new LambdaQueryWrapper() - .select(SysUser::getUserName).eq(SysUser::getUserId, userId)); + .select(SysUser::getUserName).eq(SysUser::getUserId, userId)); return ObjectUtil.isNull(sysUser) ? null : sysUser.getUserName(); } + /** + * 通过用户ID查询用户账户 + * + * @param userId 用户ID + * @return 用户账户 + */ @Override @Cacheable(cacheNames = CacheNames.SYS_NICKNAME, key = "#userId") public String selectNicknameById(Long userId) { @@ -544,4 +578,31 @@ public class SysUserServiceImpl implements ISysUserService, UserService { .select(SysUser::getNickName).eq(SysUser::getUserId, userId)); return ObjectUtil.isNull(sysUser) ? null : sysUser.getNickName(); } + + /** + * 通过用户ID查询用户手机号 + * + * @param userId 用户id + * @return 用户手机号 + */ + @Override + public String selectPhonenumberById(Long userId) { + SysUser sysUser = baseMapper.selectOne(new LambdaQueryWrapper() + .select(SysUser::getPhonenumber).eq(SysUser::getUserId, userId)); + return ObjectUtil.isNull(sysUser) ? null : sysUser.getPhonenumber(); + } + + /** + * 通过用户ID查询用户邮箱 + * + * @param userId 用户id + * @return 用户邮箱 + */ + @Override + public String selectEmailById(Long userId) { + SysUser sysUser = baseMapper.selectOne(new LambdaQueryWrapper() + .select(SysUser::getEmail).eq(SysUser::getUserId, userId)); + return ObjectUtil.isNull(sysUser) ? null : sysUser.getEmail(); + } + } diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml index bba949d7b..6ad866f29 100644 --- a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml @@ -8,11 +8,18 @@ - + select count(*) from sys_dept where del_flag = '0' and dept_id = #{deptId} - select p.post_id + - - diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml index b1916985e..7b8bba761 100644 --- a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml @@ -40,23 +40,17 @@ WHERE r.del_flag = '0' and sur.user_id = #{userId} - - - select r.role_id, r.role_name, r.role_key, - r.role_sort + r.role_sort, + r.data_scope, + r.status from sys_role r left join sys_user_role sur on sur.role_id = r.role_id left join sys_user u on u.user_id = sur.user_id - WHERE r.del_flag = '0' and u.user_name = #{userName} + WHERE r.del_flag = '0' and sur.user_id = #{userId} - select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex, - u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, - d.dept_name, d.leader, u1.user_name as leaderName + select + + ${ew.getSqlSelect} + + + u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex, + u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark + from sys_user u - left join sys_dept d on u.dept_id = d.dept_id - left join sys_user u1 on u1.user_id = d.leader ${ew.getCustomSqlSegment} + + - - - - - - - + select count(*) from sys_user where del_flag = '0' and user_id = #{userId} diff --git a/ruoyi-modules/ruoyi-workflow/pom.xml b/ruoyi-modules/ruoyi-workflow/pom.xml new file mode 100644 index 000000000..f0391e358 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/pom.xml @@ -0,0 +1,93 @@ + + + + org.dromara + ruoyi-modules + ${revision} + ../pom.xml + + 4.0.0 + jar + ruoyi-workflow + + + 工作流模块 + + + + + + + org.flowable + flowable-spring-boot-autoconfigure + + + org.flowable + flowable-spring-security + + + + + + org.flowable + flowable-spring-configurator + + + + org.flowable + flowable-spring-boot-starter-actuator + + + + + org.flowable + flowable-image-generator + + + + + org.flowable + flowable-json-converter + 6.8.0 + + + + + org.apache.xmlgraphics + batik-all + 1.10 + + + xalan + xalan + + + + + + + org.dromara + ruoyi-system + + + + org.dromara + ruoyi-common-websocket + + + + org.dromara + ruoyi-common-mail + + + + org.dromara + ruoyi-common-sms + + + + + + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/annotation/FlowListenerAnnotation.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/annotation/FlowListenerAnnotation.java new file mode 100644 index 000000000..5ea262d17 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/annotation/FlowListenerAnnotation.java @@ -0,0 +1,27 @@ +package org.dromara.workflow.annotation; + + +import java.lang.annotation.*; + +/** + * 流程任务监听注解 + * + * @author may + * @date 2023-12-27 + */ +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +public @interface FlowListenerAnnotation { + + /** + * 流程定义key + */ + String processDefinitionKey(); + + /** + * 节点id + */ + String taskDefId() default ""; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java new file mode 100644 index 000000000..df27d3cf9 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java @@ -0,0 +1,137 @@ +package org.dromara.workflow.common.constant; + + +/** + * 工作流常量 + * + * @author may + */ +public interface FlowConstant { + + String MESSAGE_CURRENT_TASK_IS_NULL = "当前任务不存在或你不是任务办理人!"; + + String MESSAGE_SUSPENDED = "当前任务已挂起不可审批!"; + + /** + * 连线 + */ + String SEQUENCE_FLOW = "sequenceFlow"; + + /** + * 并行网关 + */ + String PARALLEL_GATEWAY = "parallelGateway"; + + /** + * 排它网关 + */ + String EXCLUSIVE_GATEWAY = "exclusiveGateway"; + + /** + * 包含网关 + */ + String INCLUSIVE_GATEWAY = "inclusiveGateway"; + + /** + * 结束节点 + */ + String END_EVENT = "endEvent"; + + + /** + * 流程委派标识 + */ + String PENDING = "PENDING"; + + /** + * 候选人标识 + */ + String CANDIDATE = "candidate"; + + /** + * 会签任务总数 + */ + String NUMBER_OF_INSTANCES = "nrOfInstances"; + + /** + * 正在执行的会签总数 + */ + String NUMBER_OF_ACTIVE_INSTANCES = "nrOfActiveInstances"; + + /** + * 已完成的会签任务总数 + */ + String NUMBER_OF_COMPLETED_INSTANCES = "nrOfCompletedInstances"; + + /** + * 循环的索引值,可以使用elementIndexVariable属性修改loopCounter的变量名 + */ + String LOOP_COUNTER = "loopCounter"; + + String ZIP = "ZIP"; + + /** + * 流程实例对象 + */ + String PROCESS_INSTANCE_VO = "processInstanceVo"; + + /** + * 流程定义配置 + */ + String WF_DEFINITION_CONFIG_VO = "wfDefinitionConfigVo"; + + /** + * 节点配置 + */ + String WF_NODE_CONFIG_VO = "wfNodeConfigVo"; + + /** + * 流程发起人 + */ + String INITIATOR = "initiator"; + + /** + * 流程实例id + */ + String PROCESS_INSTANCE_ID = "processInstanceId"; + + /** + * 业务id + */ + String BUSINESS_KEY = "businessKey"; + + /** + * 流程定义id + */ + String PROCESS_DEFINITION_ID = "processDefinitionId"; + + /** + * 开启跳过表达式变量 + */ + String FLOWABLE_SKIP_EXPRESSION_ENABLED = "_FLOWABLE_SKIP_EXPRESSION_ENABLED"; + + /** + * 模型标识key命名规范正则表达式 + */ + String MODEL_KEY_PATTERN = "^[a-zA-Z][a-zA-Z0-9_]{0,254}$"; + + /** + * 用户任务 + */ + String USER_TASK = "userTask"; + + /** + * 会签 + */ + String MULTI_INSTANCE = "multiInstance"; + + /** + * 是 + */ + String TRUE = "0"; + + /** + * 否 + */ + String FALSE = "1"; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/BusinessStatusEnum.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/BusinessStatusEnum.java new file mode 100644 index 000000000..6eb6ffe6b --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/BusinessStatusEnum.java @@ -0,0 +1,152 @@ +package org.dromara.workflow.common.enums; + +import cn.hutool.core.util.StrUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.StringUtils; + +import java.util.Arrays; + +/** + * 业务状态枚举 + * + * @author may + */ +@Getter +@AllArgsConstructor +public enum BusinessStatusEnum { + /** + * 已撤销 + */ + CANCEL("cancel", "已撤销"), + /** + * 草稿 + */ + DRAFT("draft", "草稿"), + /** + * 待审核 + */ + WAITING("waiting", "待审核"), + /** + * 已完成 + */ + FINISH("finish", "已完成"), + /** + * 已作废 + */ + INVALID("invalid", "已作废"), + /** + * 已退回 + */ + BACK("back", "已退回"), + /** + * 已终止 + */ + TERMINATION("termination", "已终止"); + + /** + * 状态 + */ + private final String status; + + /** + * 描述 + */ + private final String desc; + + /** + * 获取业务状态 + * + * @param status 状态 + */ + public static String findByStatus(String status) { + if (StringUtils.isBlank(status)) { + return StrUtil.EMPTY; + } + return Arrays.stream(BusinessStatusEnum.values()) + .filter(statusEnum -> statusEnum.getStatus().equals(status)) + .findFirst() + .map(BusinessStatusEnum::getDesc) + .orElse(StrUtil.EMPTY); + } + + /** + * 启动流程校验 + * + * @param status 状态 + */ + public static void checkStartStatus(String status) { + if (WAITING.getStatus().equals(status)) { + throw new ServiceException("该单据已提交过申请,正在审批中!"); + } else if (FINISH.getStatus().equals(status)) { + throw new ServiceException("该单据已完成申请!"); + } else if (INVALID.getStatus().equals(status)) { + throw new ServiceException("该单据已作废!"); + } else if (TERMINATION.getStatus().equals(status)) { + throw new ServiceException("该单据已终止!"); + } else if (StringUtils.isBlank(status)) { + throw new ServiceException("流程状态为空!"); + } + } + + /** + * 撤销流程校验 + * + * @param status 状态 + */ + public static void checkCancelStatus(String status) { + if (CANCEL.getStatus().equals(status)) { + throw new ServiceException("该单据已撤销!"); + } else if (FINISH.getStatus().equals(status)) { + throw new ServiceException("该单据已完成申请!"); + } else if (INVALID.getStatus().equals(status)) { + throw new ServiceException("该单据已作废!"); + } else if (TERMINATION.getStatus().equals(status)) { + throw new ServiceException("该单据已终止!"); + } else if (BACK.getStatus().equals(status)) { + throw new ServiceException("该单据已退回!"); + } else if (StringUtils.isBlank(status)) { + throw new ServiceException("流程状态为空!"); + } + } + + /** + * 驳回流程校验 + * + * @param status 状态 + */ + public static void checkBackStatus(String status) { + if (BACK.getStatus().equals(status)) { + throw new ServiceException("该单据已退回!"); + } else if (FINISH.getStatus().equals(status)) { + throw new ServiceException("该单据已完成申请!"); + } else if (INVALID.getStatus().equals(status)) { + throw new ServiceException("该单据已作废!"); + } else if (TERMINATION.getStatus().equals(status)) { + throw new ServiceException("该单据已终止!"); + } else if (CANCEL.getStatus().equals(status)) { + throw new ServiceException("该单据已撤销!"); + } else if (StringUtils.isBlank(status)) { + throw new ServiceException("流程状态为空!"); + } + } + + /** + * 作废,终止流程校验 + * + * @param status 状态 + */ + public static void checkInvalidStatus(String status) { + if (FINISH.getStatus().equals(status)) { + throw new ServiceException("该单据已完成申请!"); + } else if (INVALID.getStatus().equals(status)) { + throw new ServiceException("该单据已作废!"); + } else if (TERMINATION.getStatus().equals(status)) { + throw new ServiceException("该单据已终止!"); + } else if (StringUtils.isBlank(status)) { + throw new ServiceException("流程状态为空!"); + } + } +} + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/FormTypeEnum.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/FormTypeEnum.java new file mode 100644 index 000000000..083ab7b85 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/FormTypeEnum.java @@ -0,0 +1,54 @@ +package org.dromara.workflow.common.enums; + +import cn.hutool.core.util.StrUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.apache.commons.lang3.StringUtils; + +import java.util.Arrays; + +/** + * 任务状态枚举 + * + * @author may + */ +@Getter +@AllArgsConstructor +public enum FormTypeEnum { + /** + * 自定义表单 + */ + STATIC("static", "自定义表单"), + /** + * 动态表单 + */ + DYNAMIC("dynamic", "动态表单"); + + /** + * 类型 + */ + private final String type; + + /** + * 描述 + */ + private final String desc; + + /** + * 表单类型 + * + * @param formType 表单类型 + */ + public static String findByType(String formType) { + if (StringUtils.isBlank(formType)) { + return StrUtil.EMPTY; + } + + return Arrays.stream(FormTypeEnum.values()) + .filter(statusEnum -> statusEnum.getType().equals(formType)) + .findFirst() + .map(FormTypeEnum::getDesc) + .orElse(StrUtil.EMPTY); + } +} + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/MessageTypeEnum.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/MessageTypeEnum.java new file mode 100644 index 000000000..a28295822 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/MessageTypeEnum.java @@ -0,0 +1,51 @@ +package org.dromara.workflow.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 消息类型枚举 + * + * @author may + */ +@Getter +@AllArgsConstructor +public enum MessageTypeEnum { + /** + * 站内信 + */ + SYSTEM_MESSAGE("1", "站内信"), + /** + * 邮箱 + */ + EMAIL_MESSAGE("2", "邮箱"), + /** + * 短信 + */ + SMS_MESSAGE("3", "短信"); + + private final String code; + + private final String desc; + + private final static Map MESSAGE_TYPE_ENUM_MAP = new ConcurrentHashMap<>(MessageTypeEnum.values().length); + + static { + for (MessageTypeEnum messageType : MessageTypeEnum.values()) { + MESSAGE_TYPE_ENUM_MAP.put(messageType.code, messageType); + } + } + + /** + * 根据消息类型 code 获取 MessageTypeEnum + * @param code 消息类型code + * @return MessageTypeEnum + */ + public static MessageTypeEnum getByCode(String code) { + return MESSAGE_TYPE_ENUM_MAP.get(code); + } +} + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskStatusEnum.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskStatusEnum.java new file mode 100644 index 000000000..7b2f55c20 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskStatusEnum.java @@ -0,0 +1,94 @@ +package org.dromara.workflow.common.enums; + +import cn.hutool.core.util.StrUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.apache.commons.lang3.StringUtils; + +import java.util.Arrays; + +/** + * 任务状态枚举 + * + * @author may + */ +@Getter +@AllArgsConstructor +public enum TaskStatusEnum { + /** + * 撤销 + */ + CANCEL("cancel", "撤销"), + /** + * 通过 + */ + PASS("pass", "通过"), + /** + * 待审核 + */ + WAITING("waiting", "待审核"), + /** + * 作废 + */ + INVALID("invalid", "作废"), + /** + * 退回 + */ + BACK("back", "退回"), + /** + * 终止 + */ + TERMINATION("termination", "终止"), + /** + * 转办 + */ + TRANSFER("transfer", "转办"), + /** + * 委托 + */ + PENDING("pending", "委托"), + /** + * 抄送 + */ + COPY("copy", "抄送"), + /** + * 加签 + */ + SIGN("sign", "加签"), + /** + * 减签 + */ + SIGN_OFF("sign_off", "减签"), + /** + * 超时 + */ + TIMEOUT("timeout", "超时"); + + /** + * 状态 + */ + private final String status; + + /** + * 描述 + */ + private final String desc; + + /** + * 任务业务状态 + * + * @param status 状态 + */ + public static String findByStatus(String status) { + if (StringUtils.isBlank(status)) { + return StrUtil.EMPTY; + } + + return Arrays.stream(TaskStatusEnum.values()) + .filter(statusEnum -> statusEnum.getStatus().equals(status)) + .findFirst() + .map(TaskStatusEnum::getDesc) + .orElse(StrUtil.EMPTY); + } +} + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActModelController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActModelController.java new file mode 100644 index 000000000..3332f86a5 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActModelController.java @@ -0,0 +1,147 @@ +package org.dromara.workflow.controller; + +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.workflow.domain.bo.ModelBo; +import org.dromara.workflow.domain.vo.ModelVo; +import org.dromara.workflow.service.IActModelService; +import org.flowable.engine.RepositoryService; +import org.flowable.engine.repository.Model; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.Arrays; +import java.util.List; + +/** + * 模型管理 控制层 + * + * @author may + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/workflow/model") +public class ActModelController extends BaseController { + + private final RepositoryService repositoryService; + + private final IActModelService actModelService; + + + /** + * 分页查询模型 + * + * @param modelBo 模型参数 + */ + @GetMapping("/list") + public TableDataInfo page(ModelBo modelBo, PageQuery pageQuery) { + return actModelService.page(modelBo, pageQuery); + } + + /** + * 新增模型 + * + * @param modelBo 模型请求对象 + */ + @Log(title = "模型管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/save") + public R saveNewModel(@Validated(AddGroup.class) @RequestBody ModelBo modelBo) { + return toAjax(actModelService.saveNewModel(modelBo)); + } + + /** + * 查询模型 + * + * @param id 模型id + */ + @GetMapping("/getInfo/{id}") + public R getInfo(@NotBlank(message = "模型id不能为空") @PathVariable String id) { + return R.ok(actModelService.getInfo(id)); + } + + /** + * 修改模型信息 + * + * @param modelBo 模型数据 + */ + @Log(title = "模型管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping(value = "/update") + public R update(@RequestBody ModelBo modelBo) { + return toAjax(actModelService.update(modelBo)); + } + + /** + * 编辑XMl模型 + * + * @param modelBo 模型数据 + */ + @Log(title = "模型管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping(value = "/editModelXml") + public R editModel(@Validated(EditGroup.class) @RequestBody ModelBo modelBo) { + return toAjax(actModelService.editModelXml(modelBo)); + } + + /** + * 删除流程模型 + * + * @param ids 模型id + */ + @Log(title = "模型管理", businessType = BusinessType.DELETE) + @RepeatSubmit() + @DeleteMapping("/{ids}") + @Transactional(rollbackFor = Exception.class) + public R delete(@NotEmpty(message = "主键不能为空") @PathVariable String[] ids) { + Arrays.stream(ids).parallel().forEachOrdered(repositoryService::deleteModel); + return R.ok(); + } + + /** + * 模型部署 + * + * @param id 模型id + */ + @Log(title = "模型管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/modelDeploy/{id}") + public R deploy(@NotBlank(message = "模型id不能为空") @PathVariable("id") String id) { + return toAjax(actModelService.modelDeploy(id)); + } + + /** + * 导出模型zip压缩包 + * + * @param modelIds 模型id + * @param response 相应 + */ + @GetMapping("/export/zip/{modelIds}") + public void exportZip(@NotEmpty(message = "模型id不能为空") @PathVariable List modelIds, + HttpServletResponse response) { + actModelService.exportZip(modelIds, response); + } + + /** + * 复制模型 + * + * @param modelBo 模型数据 + */ + @PostMapping("/copyModel") + public R copyModel(@RequestBody ModelBo modelBo) { + return toAjax(actModelService.copyModel(modelBo)); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActProcessDefinitionController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActProcessDefinitionController.java new file mode 100644 index 000000000..5198bd164 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActProcessDefinitionController.java @@ -0,0 +1,147 @@ +package org.dromara.workflow.controller; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.workflow.domain.bo.ProcessDefinitionBo; +import org.dromara.workflow.domain.vo.ProcessDefinitionVo; +import org.dromara.workflow.service.IActProcessDefinitionService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + + +/** + * 流程定义管理 控制层 + * + * @author may + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/workflow/processDefinition") +public class ActProcessDefinitionController extends BaseController { + + private final IActProcessDefinitionService actProcessDefinitionService; + + /** + * 分页查询 + * + * @param bo 参数 + */ + @GetMapping("/list") + public TableDataInfo page(ProcessDefinitionBo bo, PageQuery pageQuery) { + return actProcessDefinitionService.page(bo, pageQuery); + } + + /** + * 查询历史流程定义列表 + * + * @param key 流程定义key + */ + @GetMapping("/getListByKey/{key}") + public R> getListByKey(@NotEmpty(message = "流程定义key不能为空") @PathVariable String key) { + return R.ok("操作成功", actProcessDefinitionService.getListByKey(key)); + } + + /** + * 查看流程定义图片 + * + * @param processDefinitionId 流程定义id + */ + @GetMapping("/definitionImage/{processDefinitionId}") + public R definitionImage(@PathVariable String processDefinitionId) { + return R.ok("操作成功", actProcessDefinitionService.definitionImage(processDefinitionId)); + } + + /** + * 查看流程定义xml文件 + * + * @param processDefinitionId 流程定义id + */ + @GetMapping("/definitionXml/{processDefinitionId}") + public R> definitionXml(@NotBlank(message = "流程定义id不能为空") @PathVariable String processDefinitionId) { + Map map = new HashMap<>(); + String xmlStr = actProcessDefinitionService.definitionXml(processDefinitionId); + map.put("xml", Arrays.asList(xmlStr.split("\n"))); + map.put("xmlStr", xmlStr); + return R.ok(map); + } + + /** + * 删除流程定义 + * + * @param deploymentIds 部署id + * @param processDefinitionIds 流程定义id + */ + @Log(title = "流程定义管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{deploymentIds}/{processDefinitionIds}") + public R deleteDeployment(@NotNull(message = "流程部署id不能为空") @PathVariable List deploymentIds, + @NotNull(message = "流程定义id不能为空") @PathVariable List processDefinitionIds) { + return toAjax(actProcessDefinitionService.deleteDeployment(deploymentIds, processDefinitionIds)); + } + + /** + * 激活或者挂起流程定义 + * + * @param processDefinitionId 流程定义id + */ + @Log(title = "流程定义管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/updateDefinitionState/{processDefinitionId}") + public R updateDefinitionState(@NotBlank(message = "流程定义id不能为空") @PathVariable String processDefinitionId) { + return toAjax(actProcessDefinitionService.updateDefinitionState(processDefinitionId)); + } + + /** + * 迁移流程定义 + * + * @param currentProcessDefinitionId 当前流程定义id + * @param fromProcessDefinitionId 需要迁移到的流程定义id + */ + @Log(title = "流程定义管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/migrationDefinition/{currentProcessDefinitionId}/{fromProcessDefinitionId}") + public R migrationDefinition(@NotBlank(message = "当前流程定义id") @PathVariable String currentProcessDefinitionId, + @NotBlank(message = "需要迁移到的流程定义id") @PathVariable String fromProcessDefinitionId) { + return toAjax(actProcessDefinitionService.migrationDefinition(currentProcessDefinitionId, fromProcessDefinitionId)); + } + + /** + * 流程定义转换为模型 + * + * @param processDefinitionId 流程定义id + */ + @Log(title = "流程定义管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/convertToModel/{processDefinitionId}") + public R convertToModel(@NotEmpty(message = "流程定义id不能为空") @PathVariable String processDefinitionId) { + return toAjax(actProcessDefinitionService.convertToModel(processDefinitionId)); + } + + /** + * 通过zip或xml部署流程定义 + * + * @param file 文件 + * @param categoryCode 分类 + */ + @Log(title = "流程定义管理", businessType = BusinessType.INSERT) + @PostMapping("/deployByFile") + public void deployByFile(@RequestParam("file") MultipartFile file, @RequestParam("categoryCode") String categoryCode) { + actProcessDefinitionService.deployByFile(file, categoryCode); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActProcessInstanceController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActProcessInstanceController.java new file mode 100644 index 000000000..4d433df43 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActProcessInstanceController.java @@ -0,0 +1,158 @@ +package org.dromara.workflow.controller; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.workflow.domain.bo.ProcessInstanceBo; +import org.dromara.workflow.domain.bo.ProcessInvalidBo; +import org.dromara.workflow.domain.bo.TaskUrgingBo; +import org.dromara.workflow.domain.vo.ProcessInstanceVo; +import org.dromara.workflow.service.IActProcessInstanceService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.Arrays; +import java.util.Map; + +/** + * 流程实例管理 控制层 + * + * @author may + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/workflow/processInstance") +public class ActProcessInstanceController extends BaseController { + + private final IActProcessInstanceService actProcessInstanceService; + + /** + * 分页查询正在运行的流程实例 + * + * @param bo 参数 + */ + @GetMapping("/getPageByRunning") + public TableDataInfo getPageByRunning(ProcessInstanceBo bo, PageQuery pageQuery) { + return actProcessInstanceService.getPageByRunning(bo, pageQuery); + } + + /** + * 分页查询已结束的流程实例 + * + * @param bo 参数 + */ + @GetMapping("/getPageByFinish") + public TableDataInfo getPageByFinish(ProcessInstanceBo bo, PageQuery pageQuery) { + return actProcessInstanceService.getPageByFinish(bo, pageQuery); + } + + /** + * 通过流程实例id获取历史流程图 + * + * @param processInstanceId 流程实例id + */ + @GetMapping("/getHistoryImage/{processInstanceId}") + public R getHistoryImage(@NotBlank(message = "流程实例id不能为空") @PathVariable String processInstanceId) { + return R.ok("操作成功", actProcessInstanceService.getHistoryImage(processInstanceId)); + } + + /** + * 通过流程实例id获取历史流程图运行中,历史等节点 + * + * @param processInstanceId 流程实例id + */ + @GetMapping("/getHistoryList/{processInstanceId}") + public R> getHistoryList(@NotBlank(message = "流程实例id不能为空") @PathVariable String processInstanceId) { + return R.ok("操作成功", actProcessInstanceService.getHistoryList(processInstanceId)); + } + + /** + * 获取审批记录 + * + * @param processInstanceId 流程实例id + */ + @GetMapping("/getHistoryRecord/{processInstanceId}") + public R> getHistoryRecord(@NotBlank(message = "流程实例id不能为空") @PathVariable String processInstanceId) { + return R.ok(actProcessInstanceService.getHistoryRecord(processInstanceId)); + } + + /** + * 作废流程实例,不会删除历史记录(删除运行中的实例) + * + * @param processInvalidBo 参数 + */ + @Log(title = "流程实例管理", businessType = BusinessType.DELETE) + @RepeatSubmit() + @PostMapping("/deleteRunInstance") + public R deleteRunInstance(@Validated(AddGroup.class) @RequestBody ProcessInvalidBo processInvalidBo) { + return toAjax(actProcessInstanceService.deleteRunInstance(processInvalidBo)); + } + + /** + * 运行中的实例 删除程实例,删除历史记录,删除业务与流程关联信息 + * + * @param processInstanceIds 流程实例id + */ + @Log(title = "流程实例管理", businessType = BusinessType.DELETE) + @RepeatSubmit() + @DeleteMapping("/deleteRunAndHisInstance/{processInstanceIds}") + public R deleteRunAndHisInstance(@NotNull(message = "流程实例id不能为空") @PathVariable String[] processInstanceIds) { + return toAjax(actProcessInstanceService.deleteRunAndHisInstance(Arrays.asList(processInstanceIds))); + } + + /** + * 已完成的实例 删除程实例,删除历史记录,删除业务与流程关联信息 + * + * @param processInstanceIds 流程实例id + */ + @Log(title = "流程实例管理", businessType = BusinessType.DELETE) + @RepeatSubmit() + @DeleteMapping("/deleteFinishAndHisInstance/{processInstanceIds}") + public R deleteFinishAndHisInstance(@NotNull(message = "流程实例id不能为空") @PathVariable String[] processInstanceIds) { + return toAjax(actProcessInstanceService.deleteFinishAndHisInstance(Arrays.asList(processInstanceIds))); + } + + /** + * 撤销流程申请 + * + * @param processInstanceId 流程实例id + */ + @Log(title = "流程实例管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/cancelProcessApply/{processInstanceId}") + public R cancelProcessApply(@NotBlank(message = "流程实例id不能为空") @PathVariable String processInstanceId) { + return toAjax(actProcessInstanceService.cancelProcessApply(processInstanceId)); + } + + /** + * 分页查询当前登录人单据 + * + * @param bo 参数 + */ + @GetMapping("/getPageByCurrent") + public TableDataInfo getPageByCurrent(ProcessInstanceBo bo, PageQuery pageQuery) { + return actProcessInstanceService.getPageByCurrent(bo, pageQuery); + } + + /** + * 任务催办(给当前任务办理人发送站内信,邮件,短信等) + * + * @param taskUrgingBo 任务催办 + */ + @Log(title = "流程实例管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/taskUrging") + public R taskUrging(@RequestBody TaskUrgingBo taskUrgingBo) { + return toAjax(actProcessInstanceService.taskUrging(taskUrgingBo)); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActTaskController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActTaskController.java new file mode 100644 index 000000000..aa290127a --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActTaskController.java @@ -0,0 +1,274 @@ +package org.dromara.workflow.controller; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import jakarta.validation.constraints.NotBlank; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.web.core.BaseController; +import org.dromara.workflow.domain.WfTaskBackNode; +import org.dromara.workflow.domain.bo.*; +import org.dromara.workflow.domain.vo.TaskVo; +import org.dromara.workflow.domain.vo.VariableVo; +import org.dromara.workflow.service.IActTaskService; +import org.dromara.workflow.service.IWfTaskBackNodeService; +import org.dromara.workflow.utils.QueryUtils; +import org.flowable.engine.TaskService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +/** + * 任务管理 控制层 + * + * @author may + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/workflow/task") +public class ActTaskController extends BaseController { + + private final IActTaskService actTaskService; + + private final TaskService taskService; + + private final IWfTaskBackNodeService iWfTaskBackNodeService; + + + /** + * 启动任务 + * + * @param startProcessBo 启动流程参数 + */ + @Log(title = "任务管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/startWorkFlow") + public R> startWorkFlow(@Validated(AddGroup.class) @RequestBody StartProcessBo startProcessBo) { + Map map = actTaskService.startWorkFlow(startProcessBo); + return R.ok("提交成功", map); + } + + /** + * 办理任务 + * + * @param completeTaskBo 办理任务参数 + */ + @Log(title = "任务管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/completeTask") + public R completeTask(@Validated(AddGroup.class) @RequestBody CompleteTaskBo completeTaskBo) { + return toAjax(actTaskService.completeTask(completeTaskBo)); + } + + /** + * 查询当前用户的待办任务 + * + * @param taskBo 参数 + */ + @GetMapping("/getPageByTaskWait") + public TableDataInfo getPageByTaskWait(TaskBo taskBo, PageQuery pageQuery) { + return actTaskService.getPageByTaskWait(taskBo, pageQuery); + } + + /** + * 查询当前租户所有待办任务 + * + * @param taskBo 参数 + */ + @GetMapping("/getPageByAllTaskWait") + public TableDataInfo getPageByAllTaskWait(TaskBo taskBo, PageQuery pageQuery) { + return actTaskService.getPageByAllTaskWait(taskBo, pageQuery); + } + + /** + * 查询当前用户的已办任务 + * + * @param taskBo 参数 + */ + @GetMapping("/getPageByTaskFinish") + public TableDataInfo getPageByTaskFinish(TaskBo taskBo, PageQuery pageQuery) { + return actTaskService.getPageByTaskFinish(taskBo, pageQuery); + } + + /** + * 查询当前用户的抄送 + * + * @param taskBo 参数 + */ + @GetMapping("/getPageByTaskCopy") + public TableDataInfo getPageByTaskCopy(TaskBo taskBo, PageQuery pageQuery) { + return actTaskService.getPageByTaskCopy(taskBo, pageQuery); + } + + /** + * 查询当前租户所有已办任务 + * + * @param taskBo 参数 + */ + @GetMapping("/getPageByAllTaskFinish") + public TableDataInfo getPageByAllTaskFinish(TaskBo taskBo, PageQuery pageQuery) { + return actTaskService.getPageByAllTaskFinish(taskBo, pageQuery); + } + + /** + * 签收(拾取)任务 + * + * @param taskId 任务id + */ + @Log(title = "任务管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/claim/{taskId}") + public R claimTask(@NotBlank(message = "任务id不能为空") @PathVariable String taskId) { + try { + taskService.claim(taskId, Convert.toStr(LoginHelper.getUserId())); + return R.ok(); + } catch (Exception e) { + e.printStackTrace(); + return R.fail("签收任务失败:" + e.getMessage()); + } + } + + /** + * 归还(拾取的)任务 + * + * @param taskId 任务id + */ + @Log(title = "任务管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/returnTask/{taskId}") + public R returnTask(@NotBlank(message = "任务id不能为空") @PathVariable String taskId) { + try { + taskService.setAssignee(taskId, null); + return R.ok(); + } catch (Exception e) { + e.printStackTrace(); + return R.fail("归还任务失败:" + e.getMessage()); + } + } + + /** + * 委派任务 + * + * @param delegateBo 参数 + */ + @Log(title = "任务管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/delegateTask") + public R delegateTask(@Validated({AddGroup.class}) @RequestBody DelegateBo delegateBo) { + return toAjax(actTaskService.delegateTask(delegateBo)); + } + + /** + * 终止任务 + * + * @param terminationBo 参数 + */ + @Log(title = "任务管理", businessType = BusinessType.DELETE) + @RepeatSubmit() + @PostMapping("/terminationTask") + public R terminationTask(@RequestBody TerminationBo terminationBo) { + return toAjax(actTaskService.terminationTask(terminationBo)); + } + + /** + * 转办任务 + * + * @param transmitBo 参数 + */ + @Log(title = "任务管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/transferTask") + public R transferTask(@Validated({AddGroup.class}) @RequestBody TransmitBo transmitBo) { + return toAjax(actTaskService.transferTask(transmitBo)); + } + + /** + * 会签任务加签 + * + * @param addMultiBo 参数 + */ + @Log(title = "任务管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/addMultiInstanceExecution") + public R addMultiInstanceExecution(@Validated({AddGroup.class}) @RequestBody AddMultiBo addMultiBo) { + return toAjax(actTaskService.addMultiInstanceExecution(addMultiBo)); + } + + /** + * 会签任务减签 + * + * @param deleteMultiBo 参数 + */ + @Log(title = "任务管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/deleteMultiInstanceExecution") + public R deleteMultiInstanceExecution(@Validated({AddGroup.class}) @RequestBody DeleteMultiBo deleteMultiBo) { + return toAjax(actTaskService.deleteMultiInstanceExecution(deleteMultiBo)); + } + + /** + * 驳回审批 + * + * @param backProcessBo 参数 + */ + @Log(title = "任务管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/backProcess") + public R backProcess(@Validated({AddGroup.class}) @RequestBody BackProcessBo backProcessBo) { + return R.ok(actTaskService.backProcess(backProcessBo)); + } + + /** + * 获取当前任务 + * + * @param taskId 任务id + */ + @GetMapping("/getTaskById/{taskId}") + public R getTaskById(@PathVariable String taskId) { + return R.ok(QueryUtils.getTask(taskId)); + } + + + /** + * 修改任务办理人 + * + * @param taskIds 任务id + * @param userId 办理人id + */ + @Log(title = "任务管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/updateAssignee/{taskIds}/{userId}") + public R updateAssignee(@PathVariable String[] taskIds, @PathVariable String userId) { + return toAjax(actTaskService.updateAssignee(taskIds, userId)); + } + + /** + * 查询流程变量 + * + * @param taskId 任务id + */ + @GetMapping("/getInstanceVariable/{taskId}") + public R> getProcessInstVariable(@PathVariable String taskId) { + return R.ok(actTaskService.getInstanceVariable(taskId)); + } + + /** + * 获取可驳回得任务节点 + * + * @param processInstanceId 流程实例id + */ + @GetMapping("/getTaskNodeList/{processInstanceId}") + public R> getNodeList(@PathVariable String processInstanceId) { + return R.ok(CollUtil.reverse(iWfTaskBackNodeService.getListByInstanceId(processInstanceId))); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/TestLeaveController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/TestLeaveController.java new file mode 100644 index 000000000..16d92ff6c --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/TestLeaveController.java @@ -0,0 +1,107 @@ +package org.dromara.workflow.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.workflow.domain.TestLeave; +import org.dromara.workflow.domain.bo.TestLeaveBo; +import org.dromara.workflow.domain.vo.TestLeaveVo; +import org.dromara.workflow.service.ITestLeaveService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 请假 + * + * @author may + * @date 2023-07-21 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/demo/leave") +public class TestLeaveController extends BaseController { + + private final ITestLeaveService testLeaveService; + + /** + * 查询请假列表 + */ + @SaCheckPermission("demo:leave:list") + @GetMapping("/list") + public TableDataInfo list(TestLeaveBo bo, PageQuery pageQuery) { + return testLeaveService.queryPageList(bo, pageQuery); + } + + /** + * 导出请假列表 + */ + @SaCheckPermission("demo:leave:export") + @Log(title = "请假", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(TestLeaveBo bo, HttpServletResponse response) { + List list = testLeaveService.queryList(bo); + ExcelUtil.exportExcel(list, "请假", TestLeaveVo.class, response); + } + + /** + * 获取请假详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("demo:leave:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(testLeaveService.queryById(id)); + } + + /** + * 新增请假 + */ + @SaCheckPermission("demo:leave:add") + @Log(title = "请假", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody TestLeaveBo bo) { + return R.ok(testLeaveService.insertByBo(bo)); + } + + /** + * 修改请假 + */ + @SaCheckPermission("demo:leave:edit") + @Log(title = "请假", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody TestLeaveBo bo) { + return R.ok(testLeaveService.updateByBo(bo)); + } + + /** + * 删除请假 + * + * @param ids 主键串 + */ + @SaCheckPermission("demo:leave:remove") + @Log(title = "请假", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(testLeaveService.deleteWithValidByIds(List.of(ids))); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WfCategoryController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WfCategoryController.java new file mode 100644 index 000000000..8dced8929 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WfCategoryController.java @@ -0,0 +1,106 @@ +package org.dromara.workflow.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.web.core.BaseController; +import org.dromara.workflow.domain.bo.WfCategoryBo; +import org.dromara.workflow.domain.vo.WfCategoryVo; +import org.dromara.workflow.service.IWfCategoryService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 流程分类 + * + * @author may + * @date 2023-06-28 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/workflow/category") +public class WfCategoryController extends BaseController { + + private final IWfCategoryService wfCategoryService; + + /** + * 查询流程分类列表 + */ + @SaCheckPermission("workflow:category:list") + @GetMapping("/list") + public R> list(WfCategoryBo bo) { + List list = wfCategoryService.queryList(bo); + return R.ok(list); + + } + + /** + * 导出流程分类列表 + */ + @SaCheckPermission("workflow:category:export") + @Log(title = "流程分类", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(WfCategoryBo bo, HttpServletResponse response) { + List list = wfCategoryService.queryList(bo); + ExcelUtil.exportExcel(list, "流程分类", WfCategoryVo.class, response); + } + + /** + * 获取流程分类详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("workflow:category:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(wfCategoryService.queryById(id)); + } + + /** + * 新增流程分类 + */ + @SaCheckPermission("workflow:category:add") + @Log(title = "流程分类", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody WfCategoryBo bo) { + return toAjax(wfCategoryService.insertByBo(bo)); + } + + /** + * 修改流程分类 + */ + @SaCheckPermission("workflow:category:edit") + @Log(title = "流程分类", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody WfCategoryBo bo) { + return toAjax(wfCategoryService.updateByBo(bo)); + } + + /** + * 删除流程分类 + * + * @param ids 主键串 + */ + @SaCheckPermission("workflow:category:remove") + @Log(title = "流程分类", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(wfCategoryService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WfDefinitionConfigController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WfDefinitionConfigController.java new file mode 100644 index 000000000..176aba2e4 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WfDefinitionConfigController.java @@ -0,0 +1,79 @@ +package org.dromara.workflow.controller; + +import java.util.List; + +import lombok.RequiredArgsConstructor; +import jakarta.validation.constraints.*; +import org.dromara.workflow.domain.bo.WfDefinitionConfigBo; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.workflow.domain.vo.WfDefinitionConfigVo; +import org.dromara.workflow.service.IWfDefinitionConfigService; + +/** + * 流程定义配置 + * + * @author may + * @date 2024-03-18 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/workflow/definitionConfig") +public class WfDefinitionConfigController extends BaseController { + + private final IWfDefinitionConfigService wfDefinitionConfigService; + + + /** + * 获取流程定义配置详细信息 + * + * @param definitionId 主键 + */ + @GetMapping("/getByDefId/{definitionId}") + public R getByDefId(@NotBlank(message = "流程定义ID不能为空") + @PathVariable String definitionId) { + return R.ok(wfDefinitionConfigService.getByDefId(definitionId)); + } + + /** + * 新增流程定义配置 + */ + @Log(title = "流程定义配置", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/saveOrUpdate") + public R saveOrUpdate(@Validated(AddGroup.class) @RequestBody WfDefinitionConfigBo bo) { + return toAjax(wfDefinitionConfigService.saveOrUpdate(bo)); + } + + /** + * 删除流程定义配置 + * + * @param ids 主键串 + */ + @Log(title = "流程定义配置", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(wfDefinitionConfigService.deleteByIds(List.of(ids))); + } + + /** + * 查询流程定义配置排除当前查询的流程定义 + * + * @param tableName 表名 + * @param definitionId 流程定义id + */ + @GetMapping("/getByTableNameNotDefId/{tableName}/{definitionId}") + public R> getByTableNameNotDefId(@NotBlank(message = "表名不能为空") @PathVariable String tableName, + @NotBlank(message = "流程定义ID不能为空") @PathVariable String definitionId) { + return R.ok(wfDefinitionConfigService.getByTableNameNotDefId(tableName, definitionId)); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WfFormManageController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WfFormManageController.java new file mode 100644 index 000000000..198e233b4 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WfFormManageController.java @@ -0,0 +1,114 @@ +package org.dromara.workflow.controller; + +import java.util.List; + +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.workflow.domain.vo.WfFormManageVo; +import org.dromara.workflow.domain.bo.WfFormManageBo; +import org.dromara.workflow.service.IWfFormManageService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 表单管理 + * + * @author may + * @date 2024-03-29 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/workflow/formManage") +public class WfFormManageController extends BaseController { + + private final IWfFormManageService wfFormManageService; + + /** + * 查询表单管理列表 + */ + @SaCheckPermission("workflow:formManage:list") + @GetMapping("/list") + public TableDataInfo list(WfFormManageBo bo, PageQuery pageQuery) { + return wfFormManageService.queryPageList(bo, pageQuery); + } + + /** + * 查询表单管理列表 + */ + @SaCheckPermission("workflow:formManage:list") + @GetMapping("/list/selectList") + public R> selectList() { + return R.ok(wfFormManageService.selectList()); + } + + /** + * 导出表单管理列表 + */ + @SaCheckPermission("workflow:formManage:export") + @Log(title = "表单管理", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(WfFormManageBo bo, HttpServletResponse response) { + List list = wfFormManageService.queryList(bo); + ExcelUtil.exportExcel(list, "表单管理", WfFormManageVo.class, response); + } + + /** + * 获取表单管理详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("workflow:formManage:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(wfFormManageService.queryById(id)); + } + + /** + * 新增表单管理 + */ + @SaCheckPermission("workflow:formManage:add") + @Log(title = "表单管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody WfFormManageBo bo) { + return toAjax(wfFormManageService.insertByBo(bo)); + } + + /** + * 修改表单管理 + */ + @SaCheckPermission("workflow:formManage:edit") + @Log(title = "表单管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody WfFormManageBo bo) { + return toAjax(wfFormManageService.updateByBo(bo)); + } + + /** + * 删除表单管理 + * + * @param ids 主键串 + */ + @SaCheckPermission("workflow:formManage:remove") + @Log(title = "表单管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(wfFormManageService.deleteByIds(List.of(ids))); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WorkflowUserController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WorkflowUserController.java new file mode 100644 index 000000000..d553ad8f5 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WorkflowUserController.java @@ -0,0 +1,72 @@ +package org.dromara.workflow.controller; + +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.bo.SysUserBo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.workflow.domain.bo.SysUserMultiBo; +import org.dromara.workflow.domain.vo.TaskVo; +import org.dromara.workflow.service.IWorkflowUserService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + + +/** + * 工作流用户选人管理 控制层 + * + * @author may + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/workflow/user") +public class WorkflowUserController extends BaseController { + + private final IWorkflowUserService workflowUserService; + + /** + * 分页查询工作流选择加签人员 + * + * @param bo 参数 + */ + @GetMapping("/getPageByAddMultiInstance") + public TableDataInfo getPageByAddMultiInstance(SysUserMultiBo bo, PageQuery pageQuery) { + return workflowUserService.getPageByAddMultiInstance(bo, pageQuery); + } + + /** + * 查询工作流选择减签人员 + * + * @param taskId 任务id + */ + @GetMapping("/getListByDeleteMultiInstance/{taskId}") + public R> getListByDeleteMultiInstance(@PathVariable String taskId) { + return R.ok(workflowUserService.getListByDeleteMultiInstance(taskId)); + } + + /** + * 按照用户id查询用户 + * + * @param userIds 用户id + */ + @GetMapping("/getUserListByIds/{userIds}") + public R> getUserListByIds(@PathVariable List userIds) { + return R.ok(workflowUserService.getUserListByIds(userIds)); + } + + /** + * 分页查询用户 + * + * @param sysUserBo 参数 + * @param pageQuery 分页 + */ + @GetMapping("/getPageByUserList") + public TableDataInfo getPageByUserList(SysUserBo sysUserBo, PageQuery pageQuery) { + return workflowUserService.getPageByUserList(sysUserBo, pageQuery); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/ActHiProcinst.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/ActHiProcinst.java new file mode 100644 index 000000000..e87fb9253 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/ActHiProcinst.java @@ -0,0 +1,152 @@ +package org.dromara.workflow.domain; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 流程实例对象 act_hi_procinst + * + * @author may + * @date 2023-07-22 + */ +@Data +@TableName("act_hi_procinst") +public class ActHiProcinst implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + @TableId(value = "ID_") + private String id; + + /** + * + */ + @TableField(value = "REV_") + private Long rev; + + /** + * + */ + @TableField(value = "PROC_INST_ID_") + private String procInstId; + + /** + * + */ + @TableField(value = "BUSINESS_KEY_") + private String businessKey; + + /** + * + */ + @TableField(value = "PROC_DEF_ID_") + private String procDefId; + + /** + * + */ + @TableField(value = "START_TIME_") + private Date startTime; + + /** + * + */ + @TableField(value = "END_TIME_") + private Date endTime; + + /** + * + */ + @TableField(value = "DURATION_") + private Long duration; + + /** + * + */ + @TableField(value = "START_USER_ID_") + private String startUserId; + + /** + * + */ + @TableField(value = "START_ACT_ID_") + private String startActId; + + /** + * + */ + @TableField(value = "END_ACT_ID_") + private String endActId; + + /** + * + */ + @TableField(value = "SUPER_PROCESS_INSTANCE_ID_") + private String superProcessInstanceId; + + /** + * + */ + @TableField(value = "DELETE_REASON_") + private String deleteReason; + + /** + * + */ + @TableField(value = "TENANT_ID_") + private String tenantId; + + /** + * + */ + @TableField(value = "NAME_") + private String name; + + /** + * + */ + @TableField(value = "CALLBACK_ID_") + private String callbackId; + + /** + * + */ + @TableField(value = "CALLBACK_TYPE_") + private String callbackType; + + /** + * + */ + @TableField(value = "REFERENCE_ID_") + private String referenceId; + + /** + * + */ + @TableField(value = "REFERENCE_TYPE_") + private String referenceType; + + /** + * + */ + @TableField(value = "PROPAGATED_STAGE_INST_ID_") + private String propagatedStageInstId; + + /** + * + */ + @TableField(value = "BUSINESS_STATUS_") + private String businessStatus; + + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/ActHiTaskinst.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/ActHiTaskinst.java new file mode 100644 index 000000000..abc17b54c --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/ActHiTaskinst.java @@ -0,0 +1,193 @@ +package org.dromara.workflow.domain; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +import java.io.Serial; + +/** + * 流程历史任务对象 act_hi_taskinst + * + * @author may + * @date 2024-03-02 + */ +@Data +@TableName("act_hi_taskinst") +public class ActHiTaskinst implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + @TableId(value = "ID_") + private String id; + + /** + * 版本 + */ + @TableField(value = "REV_") + private Long rev; + + /** + * 流程定义id + */ + @TableField(value = "PROC_DEF_ID_") + private String procDefId; + + /** + * + */ + @TableField(value = "TASK_DEF_ID_") + private String taskDefId; + + /** + * 任务节点id + */ + @TableField(value = "TASK_DEF_KEY_") + private String taskDefKey; + + /** + * 流程实例id + */ + @TableField(value = "PROC_INST_ID_") + private String procInstId; + + /** + * 流程执行id + */ + @TableField(value = "EXECUTION_ID") + private String executionId; + + /** + * + */ + @TableField(value = "SCOPE_ID_") + private String scopeId; + + /** + * + */ + @TableField(value = "SUB_SCOPE_ID_") + private String subScopeId; + + /** + * 先用当前字段标识抄送类型 + */ + @TableField(value = "SCOPE_TYPE_") + private String scopeType; + + /** + * + */ + @TableField(value = "SCOPE_DEFINITION_ID_") + private String scopeDefinitionId; + + /** + * + */ + @TableField(value = "PROPAGATED_STAGE_INST_ID_") + private String propagatedStageInstId; + + /** + * 任务名称 + */ + @TableField(value = "NAME_") + private String name; + + /** + * 父级id + */ + @TableField(value = "PARENT_TASK_ID_") + private String parentTaskId; + + /** + * 描述 + */ + @TableField(value = "DESCRIPTION_") + private String description; + + /** + * 办理人 + */ + @TableField(value = "OWNER_") + private String owner; + + /** + * 办理人 + */ + @TableField(value = "ASSIGNEE_") + private String assignee; + + /** + * 开始事件 + */ + @TableField(value = "START_TIME_") + private Date startTime; + + /** + * 认领时间 + */ + @TableField(value = "CLAIM_TIME_") + private Date claimTime; + + /** + * 结束时间 + */ + @TableField(value = "END_TIME_") + private Date endTime; + + /** + * 持续时间 + */ + @TableField(value = "DURATION_") + private Long duration; + + /** + * 删除原因 + */ + @TableField(value = "DELETE_REASON_") + private String deleteReason; + + /** + * 优先级 + */ + @TableField(value = "PRIORITY_") + private Long priority; + + /** + * 到期时间 + */ + @TableField(value = "DUE_DATE_") + private Date dueDate; + + /** + * + */ + @TableField(value = "FORM_KEY_") + private String formKey; + + /** + * 分类 + */ + @TableField(value = "CATEGORY_") + private String category; + + /** + * 最后修改时间 + */ + @TableField(value = "LAST_UPDATED_TIME_") + private Date lastUpdatedTime; + + /** + * 租户id + */ + @TableField(value = "TENANT_ID_") + private String tenantId; + + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/TestLeave.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/TestLeave.java new file mode 100644 index 000000000..0e2646701 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/TestLeave.java @@ -0,0 +1,58 @@ +package org.dromara.workflow.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.util.Date; + +/** + * 请假对象 test_leave + * + * @author may + * @date 2023-07-21 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("test_leave") +public class TestLeave extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 请假类型 + */ + private String leaveType; + + /** + * 开始时间 + */ + private Date startDate; + + /** + * 结束时间 + */ + private Date endDate; + + /** + * 请假天数 + */ + private Integer leaveDays; + + /** + * 请假原因 + */ + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfCategory.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfCategory.java new file mode 100644 index 000000000..94a7cf500 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfCategory.java @@ -0,0 +1,52 @@ +package org.dromara.workflow.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.tenant.core.TenantEntity; + +import java.io.Serial; + +/** + * 流程分类对象 wf_category + * + * @author may + * @date 2023-06-27 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("wf_category") +public class WfCategory extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 分类名称 + */ + private String categoryName; + + /** + * 分类编码 + */ + private String categoryCode; + + /** + * 父级id + */ + private Long parentId; + + /** + * 排序 + */ + private Long sortNum; + + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfDefinitionConfig.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfDefinitionConfig.java new file mode 100644 index 000000000..11dcaa081 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfDefinitionConfig.java @@ -0,0 +1,56 @@ +package org.dromara.workflow.domain; + +import org.dromara.common.mybatis.core.domain.BaseEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; + +/** + * 流程定义配置对象 wf_definition_config + * + * @author may + * @date 2024-03-18 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("wf_definition_config") +public class WfDefinitionConfig extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 表名 + */ + private String tableName; + + /** + * 流程定义ID + */ + private String definitionId; + + /** + * 流程KEY + */ + private String processKey; + + /** + * 流程版本 + */ + private Integer version; + + /** + * 备注 + */ + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfFormManage.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfFormManage.java new file mode 100644 index 000000000..47f0d7a58 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfFormManage.java @@ -0,0 +1,51 @@ +package org.dromara.workflow.domain; + +import org.dromara.common.tenant.core.TenantEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; + +/** + * 表单管理对象 wf_form_manage + * + * @author may + * @date 2024-03-29 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("wf_form_manage") +public class WfFormManage extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 表单名称 + */ + private String formName; + + /** + * 表单类型 + */ + private String formType; + + /** + * 路由地址/表单ID + */ + private String router; + + /** + * 备注 + */ + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfNodeConfig.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfNodeConfig.java new file mode 100644 index 000000000..999425f53 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfNodeConfig.java @@ -0,0 +1,61 @@ +package org.dromara.workflow.domain; + +import org.dromara.common.tenant.core.TenantEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; + +/** + * 节点配置对象 wf_node_config + * + * @author may + * @date 2024-03-30 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("wf_node_config") +public class WfNodeConfig extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 表单id + */ + private Long formId; + + /** + * 表单类型 + */ + private String formType; + + /** + * 节点名称 + */ + private String nodeName; + + /** + * 节点id + */ + private String nodeId; + + /** + * 流程定义id + */ + private String definitionId; + + /** + * 是否为申请人节点 (0是 1否) + */ + private String applyUserTask; + + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfTaskBackNode.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfTaskBackNode.java new file mode 100644 index 000000000..6f5972794 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfTaskBackNode.java @@ -0,0 +1,61 @@ +package org.dromara.workflow.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.tenant.core.TenantEntity; + +import java.io.Serial; + +/** + * 节点驳回记录 wf_task_back_node + * + * @author may + * @date 2024-03-13 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("wf_task_back_node") +public class WfTaskBackNode extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 实例id + */ + private String instanceId; + + /** + * 节点id + */ + private String nodeId; + + /** + * 节点名称 + */ + private String nodeName; + + /** + * 排序 + */ + private Integer orderNo; + + /** + * 节点类型 + */ + private String taskType; + + /** + * 办理人 + */ + private String assignee; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/AddMultiBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/AddMultiBo.java new file mode 100644 index 000000000..320ec64ca --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/AddMultiBo.java @@ -0,0 +1,40 @@ +package org.dromara.workflow.domain.bo; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * 加签参数请求 + * + * @author may + */ +@Data +public class AddMultiBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 任务ID + */ + @NotBlank(message = "任务ID不能为空", groups = AddGroup.class) + private String taskId; + + /** + * 加签人员id + */ + @NotEmpty(message = "加签人员不能为空", groups = AddGroup.class) + private List assignees; + + /** + * 加签人员名称 + */ + @NotEmpty(message = "加签人员不能为空", groups = AddGroup.class) + private List assigneeNames; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java new file mode 100644 index 000000000..d0f436925 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java @@ -0,0 +1,44 @@ +package org.dromara.workflow.domain.bo; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + + +/** + * 驳回参数请求 + * + * @author may + */ +@Data +public class BackProcessBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 任务ID + */ + @NotBlank(message = "任务ID不能为空", groups = AddGroup.class) + private String taskId; + + /** + * 消息类型 + */ + private List messageType; + + /** + * 驳回的节点id(目前未使用,直接驳回到申请人) + */ + @NotBlank(message = "驳回的节点不能为空", groups = AddGroup.class) + private String targetActivityId; + + /** + * 办理意见 + */ + private String message; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/CompleteTaskBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/CompleteTaskBo.java new file mode 100644 index 000000000..062390551 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/CompleteTaskBo.java @@ -0,0 +1,65 @@ +package org.dromara.workflow.domain.bo; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.workflow.domain.vo.WfCopy; + +import java.io.Serial; +import java.io.Serializable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * 办理任务请求对象 + * + * @author may + */ +@Data +public class CompleteTaskBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 任务id + */ + @NotBlank(message = "任务id不能为空", groups = {AddGroup.class}) + private String taskId; + + /** + * 附件id + */ + private String fileId; + + /** + * 抄送人员 + */ + private List wfCopyList; + + /** + * 消息类型 + */ + private List messageType; + + /** + * 办理意见 + */ + private String message; + + /** + * 流程变量 + */ + private Map variables; + + public Map getVariables() { + if (variables == null) { + return new HashMap<>(16); + } + variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); + return variables; + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/DelegateBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/DelegateBo.java new file mode 100644 index 000000000..a6846a6d6 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/DelegateBo.java @@ -0,0 +1,38 @@ +package org.dromara.workflow.domain.bo; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 委派任务请求对象 + * + * @author may + */ +@Data +public class DelegateBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 委派人id + */ + @NotBlank(message = "委派人id不能为空", groups = {AddGroup.class}) + private String userId; + + /** + * 委派人名称 + */ + @NotBlank(message = "委派人名称不能为空", groups = {AddGroup.class}) + private String nickName; + + /** + * 任务id + */ + @NotBlank(message = "任务id不能为空", groups = {AddGroup.class}) + private String taskId; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/DeleteMultiBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/DeleteMultiBo.java new file mode 100644 index 000000000..e533167d9 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/DeleteMultiBo.java @@ -0,0 +1,52 @@ +package org.dromara.workflow.domain.bo; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * 减签参数请求 + * + * @author may + */ +@Data +public class DeleteMultiBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 任务ID + */ + @NotBlank(message = "任务ID不能为空", groups = AddGroup.class) + private String taskId; + + /** + * 减签人员 + */ + @NotEmpty(message = "减签人员不能为空", groups = AddGroup.class) + private List taskIds; + + /** + * 执行id + */ + @NotEmpty(message = "执行id不能为空", groups = AddGroup.class) + private List executionIds; + + /** + * 人员id + */ + @NotEmpty(message = "减签人员id不能为空", groups = AddGroup.class) + private List assigneeIds; + + /** + * 人员名称 + */ + @NotEmpty(message = "减签人员不能为空", groups = AddGroup.class) + private List assigneeNames; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ModelBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ModelBo.java new file mode 100644 index 000000000..efe9acddb --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ModelBo.java @@ -0,0 +1,66 @@ +package org.dromara.workflow.domain.bo; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.workflow.common.constant.FlowConstant; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 模型请求对象 + * + * @author may + */ +@Data +public class ModelBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 模型id + */ + @NotBlank(message = "模型ID不能为空", groups = {EditGroup.class}) + private String id; + + /** + * 模型名称 + */ + @NotBlank(message = "模型名称不能为空", groups = {AddGroup.class}) + private String name; + + /** + * 模型标识key + */ + @NotBlank(message = "模型标识key不能为空", groups = {AddGroup.class}) + @Pattern(regexp = FlowConstant.MODEL_KEY_PATTERN, message = "模型标识key只能字符或者下划线开头", groups = {AddGroup.class}) + private String key; + + /** + * 模型分类 + */ + @NotBlank(message = "模型分类不能为空", groups = {AddGroup.class}) + private String categoryCode; + + /** + * 模型XML + */ + @NotBlank(message = "模型XML不能为空", groups = {AddGroup.class}) + private String xml; + + /** + * 模型SVG图片 + */ + @NotBlank(message = "模型SVG不能为空", groups = {EditGroup.class}) + private String svg; + + /** + * 备注 + */ + private String description; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessDefinitionBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessDefinitionBo.java new file mode 100644 index 000000000..2025932ba --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessDefinitionBo.java @@ -0,0 +1,34 @@ +package org.dromara.workflow.domain.bo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 流程定义请求对象 + * + * @author may + */ +@Data +public class ProcessDefinitionBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 流程定义名称key + */ + private String key; + + /** + * 流程定义名称 + */ + private String name; + + /** + * 模型分类 + */ + private String categoryCode; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessInstanceBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessInstanceBo.java new file mode 100644 index 000000000..2833b3ecb --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessInstanceBo.java @@ -0,0 +1,43 @@ +package org.dromara.workflow.domain.bo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 流程实例请求对象 + * + * @author may + */ +@Data +public class ProcessInstanceBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 流程名称 + */ + private String name; + + /** + * 流程key + */ + private String key; + + /** + * 任务发起人 + */ + private String startUserId; + + /** + * 业务id + */ + private String businessKey; + + /** + * 模型分类 + */ + private String categoryCode; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessInvalidBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessInvalidBo.java new file mode 100644 index 000000000..35d565255 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessInvalidBo.java @@ -0,0 +1,31 @@ +package org.dromara.workflow.domain.bo; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 流程实例作废请求对象 + * + * @author may + */ +@Data +public class ProcessInvalidBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 流程实例id + */ + @NotBlank(message = "流程实例id不能为空", groups = {AddGroup.class}) + private String processInstanceId; + + /** + * 作废原因 + */ + private String deleteReason; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java new file mode 100644 index 000000000..7af7935e6 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java @@ -0,0 +1,49 @@ +package org.dromara.workflow.domain.bo; + + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; + +import java.io.Serial; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * 启动流程对象 + * + * @author may + */ +@Data +public class StartProcessBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 业务唯一值id + */ + @NotBlank(message = "业务ID不能为空", groups = {AddGroup.class}) + private String businessKey; + + /** + * 表名 + */ + @NotBlank(message = "表名不能为空", groups = {AddGroup.class}) + private String tableName; + + /** + * 流程变量,前端会提交一个元素{'entity': {业务详情数据对象}} + */ + private Map variables; + + public Map getVariables() { + if (variables == null) { + return new HashMap<>(16); + } + variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); + return variables; + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/SysUserMultiBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/SysUserMultiBo.java new file mode 100644 index 000000000..e4d99e47a --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/SysUserMultiBo.java @@ -0,0 +1,39 @@ +package org.dromara.workflow.domain.bo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 用户加签查询 + * + * @author may + */ +@Data +public class SysUserMultiBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 人员名称 + */ + private String userName; + + /** + * 人员名称 + */ + private String nickName; + + /** + * 部门id + */ + private String deptId; + + /** + * 任务id + */ + private String taskId; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskBo.java new file mode 100644 index 000000000..303747939 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskBo.java @@ -0,0 +1,33 @@ +package org.dromara.workflow.domain.bo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 任务请求对象 + * + * @author may + */ +@Data +public class TaskBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 任务名称 + */ + private String name; + + /** + * 流程定义名称 + */ + private String processDefinitionName; + + /** + * 流程定义key + */ + private String processDefinitionKey; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskUrgingBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskUrgingBo.java new file mode 100644 index 000000000..20856efa9 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskUrgingBo.java @@ -0,0 +1,34 @@ +package org.dromara.workflow.domain.bo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * 任务催办 + * + * @author may + */ +@Data +public class TaskUrgingBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 流程实例id + */ + private String processInstanceId; + + /** + * 消息类型 + */ + private List messageType; + + /** + * 催办内容(为空默认系统内置信息) + */ + private String message; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TerminationBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TerminationBo.java new file mode 100644 index 000000000..8f2206e82 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TerminationBo.java @@ -0,0 +1,31 @@ +package org.dromara.workflow.domain.bo; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 终止任务请求对象 + * + * @author may + */ +@Data +public class TerminationBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 任务id + */ + @NotBlank(message = "任务id为空", groups = AddGroup.class) + private String taskId; + + /** + * 审批意见 + */ + private String comment; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TestLeaveBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TestLeaveBo.java new file mode 100644 index 000000000..e71be591a --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TestLeaveBo.java @@ -0,0 +1,75 @@ +package org.dromara.workflow.domain.bo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.workflow.domain.TestLeave; + +import java.util.Date; + +/** + * 请假业务对象 test_leave + * + * @author may + * @date 2023-07-21 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = TestLeave.class, reverseConvertGenerate = false) +public class TestLeaveBo extends BaseEntity { + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = {EditGroup.class}) + private Long id; + + /** + * 请假类型 + */ + @NotBlank(message = "请假类型不能为空", groups = {AddGroup.class, EditGroup.class}) + private String leaveType; + + /** + * 开始时间 + */ + @NotNull(message = "开始时间不能为空", groups = {AddGroup.class, EditGroup.class}) + @JsonFormat(pattern = "yyyy-MM-dd") + private Date startDate; + + /** + * 结束时间 + */ + @NotNull(message = "结束时间不能为空", groups = {AddGroup.class, EditGroup.class}) + @JsonFormat(pattern = "yyyy-MM-dd") + private Date endDate; + + /** + * 请假天数 + */ + @NotNull(message = "请假天数不能为空", groups = {AddGroup.class, EditGroup.class}) + private Integer leaveDays; + + /** + * 开始时间 + */ + private Integer startLeaveDays; + + /** + * 结束时间 + */ + private Integer endLeaveDays; + + /** + * 请假原因 + */ + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TransmitBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TransmitBo.java new file mode 100644 index 000000000..3eb6609fd --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TransmitBo.java @@ -0,0 +1,37 @@ +package org.dromara.workflow.domain.bo; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 终转办务请求对象 + * + * @author may + */ +@Data +public class TransmitBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 任务id + */ + @NotBlank(message = "任务id为空", groups = AddGroup.class) + private String taskId; + + /** + * 转办人id + */ + @NotBlank(message = "转办人不能为空", groups = AddGroup.class) + private String userId; + + /** + * 审批意见 + */ + private String comment; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfCategoryBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfCategoryBo.java new file mode 100644 index 000000000..69608fda3 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfCategoryBo.java @@ -0,0 +1,54 @@ +package org.dromara.workflow.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.workflow.domain.WfCategory; + +/** + * 流程分类业务对象 wf_category + * + * @author may + * @date 2023-06-27 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = WfCategory.class, reverseConvertGenerate = false) +public class WfCategoryBo extends BaseEntity { + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = {EditGroup.class}) + private Long id; + + /** + * 分类名称 + */ + @NotBlank(message = "分类名称不能为空", groups = {AddGroup.class, EditGroup.class}) + private String categoryName; + + /** + * 分类编码 + */ + @NotBlank(message = "分类编码不能为空", groups = {AddGroup.class, EditGroup.class}) + private String categoryCode; + + /** + * 父级id + */ + @NotNull(message = "父级id不能为空", groups = {AddGroup.class, EditGroup.class}) + private Long parentId; + + /** + * 排序 + */ + private Long sortNum; + + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfDefinitionConfigBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfDefinitionConfigBo.java new file mode 100644 index 000000000..fac17709a --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfDefinitionConfigBo.java @@ -0,0 +1,59 @@ +package org.dromara.workflow.domain.bo; + +import org.dromara.workflow.domain.WfDefinitionConfig; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; + +/** + * 流程定义配置业务对象 wf_form_definition + * + * @author may + * @date 2024-03-18 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = WfDefinitionConfig.class, reverseConvertGenerate = false) +public class WfDefinitionConfigBo extends BaseEntity { + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = {EditGroup.class}) + private Long id; + + /** + * 表名 + */ + @NotBlank(message = "表名不能为空", groups = {AddGroup.class}) + private String tableName; + + /** + * 流程定义ID + */ + @NotBlank(message = "流程定义ID不能为空", groups = {AddGroup.class}) + private String definitionId; + + /** + * 流程KEY + */ + @NotBlank(message = "流程KEY不能为空", groups = {AddGroup.class}) + private String processKey; + + /** + * 流程版本 + */ + @NotNull(message = "流程版本不能为空", groups = {AddGroup.class}) + private Integer version; + + /** + * 备注 + */ + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfFormManageBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfFormManageBo.java new file mode 100644 index 000000000..8afc286db --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfFormManageBo.java @@ -0,0 +1,53 @@ +package org.dromara.workflow.domain.bo; + +import org.dromara.workflow.domain.WfFormManage; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; + +/** + * 表单管理业务对象 wf_form_manage + * + * @author may + * @date 2024-03-29 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = WfFormManage.class, reverseConvertGenerate = false) +public class WfFormManageBo extends BaseEntity { + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 表单名称 + */ + @NotBlank(message = "表单名称不能为空", groups = { AddGroup.class, EditGroup.class }) + private String formName; + + /** + * 表单类型 + */ + @NotBlank(message = "表单类型不能为空", groups = { AddGroup.class, EditGroup.class }) + private String formType; + /** + * 路由地址/表单ID + */ + @NotBlank(message = "路由地址/表单ID不能为空", groups = { AddGroup.class, EditGroup.class }) + private String router; + + + /** + * 备注 + */ + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfNodeConfigBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfNodeConfigBo.java new file mode 100644 index 000000000..de518d3dd --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfNodeConfigBo.java @@ -0,0 +1,63 @@ +package org.dromara.workflow.domain.bo; + +import org.dromara.workflow.domain.WfNodeConfig; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; + +/** + * 节点配置业务对象 wf_node_config + * + * @author may + * @date 2024-03-30 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = WfNodeConfig.class, reverseConvertGenerate = false) +public class WfNodeConfigBo extends BaseEntity { + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = {EditGroup.class}) + private Long id; + + /** + * 表单id + */ + private Long formId; + + /** + * 表单类型 + */ + private String formType; + + /** + * 节点名称 + */ + @NotBlank(message = "节点名称不能为空", groups = {AddGroup.class, EditGroup.class}) + private String nodeName; + + /** + * 节点id + */ + @NotBlank(message = "节点id不能为空", groups = {AddGroup.class, EditGroup.class}) + private String nodeId; + + /** + * 流程定义id + */ + @NotBlank(message = "流程定义id不能为空", groups = {AddGroup.class, EditGroup.class}) + private String definitionId; + + /** + * 是否为申请人节点 (0是 1否) + */ + @NotBlank(message = "是否为申请人节点不能为空", groups = {AddGroup.class, EditGroup.class}) + private String applyUserTask; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ActHistoryInfoVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ActHistoryInfoVo.java new file mode 100644 index 000000000..459b2d0f6 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ActHistoryInfoVo.java @@ -0,0 +1,89 @@ +package org.dromara.workflow.domain.vo; + +import lombok.Data; +import org.dromara.common.translation.annotation.Translation; +import org.dromara.common.translation.constant.TransConstant; +import org.flowable.engine.task.Attachment; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * 流程审批记录视图 + * + * @author may + */ +@Data +public class ActHistoryInfoVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + /** + * 任务id + */ + private String id; + /** + * 节点id + */ + private String taskDefinitionKey; + /** + * 任务名称 + */ + private String name; + /** + * 流程实例id + */ + private String processInstanceId; + /** + * 开始时间 + */ + private Date startTime; + /** + * 结束时间 + */ + private Date endTime; + /** + * 运行时长 + */ + private String runDuration; + /** + * 状态 + */ + private String status; + /** + * 状态 + */ + private String statusName; + /** + * 办理人id + */ + private Long assignee; + + /** + * 办理人名称 + */ + @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "assignee") + private String nickName; + + /** + * 办理人id + */ + private String owner; + + /** + * 审批信息id + */ + private String commentId; + + /** + * 审批信息 + */ + private String comment; + + /** + * 审批附件 + */ + private List attachmentList; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/GraphicInfoVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/GraphicInfoVo.java new file mode 100644 index 000000000..763613165 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/GraphicInfoVo.java @@ -0,0 +1,47 @@ +package org.dromara.workflow.domain.vo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 节点图形信息 + * + * @author may + */ +@Data +public class GraphicInfoVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + /** + * x坐标 + */ + private double x; + + /** + * y坐标 + */ + private double y; + + /** + * 节点高度 + */ + private double height; + + /** + * 节点宽度 + */ + private double width; + + /** + * 节点id + */ + private String nodeId; + + /** + * 节点名称 + */ + private String nodeName; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ModelVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ModelVo.java new file mode 100644 index 000000000..b2ce81108 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ModelVo.java @@ -0,0 +1,48 @@ +package org.dromara.workflow.domain.vo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 模型视图对象 + * + * @author may + */ +@Data +public class ModelVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 模型id + */ + private String id; + + /** + * 模型名称 + */ + private String name; + + /** + * 模型标识key + */ + private String key; + + /** + * 模型分类 + */ + private String categoryCode; + + /** + * 模型XML + */ + private String xml; + + /** + * 备注 + */ + private String description; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/MultiInstanceVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/MultiInstanceVo.java new file mode 100644 index 000000000..b99839603 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/MultiInstanceVo.java @@ -0,0 +1,33 @@ +package org.dromara.workflow.domain.vo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 多实例信息 + * + * @author may + */ +@Data +public class MultiInstanceVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 会签类型(串行,并行) + */ + private Object type; + + /** + * 会签人员KEY + */ + private String assignee; + + /** + * 会签人员集合KEY + */ + private String assigneeList; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ParticipantVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ParticipantVo.java new file mode 100644 index 000000000..c5876f689 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ParticipantVo.java @@ -0,0 +1,43 @@ +package org.dromara.workflow.domain.vo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * 参与者 + * + * @author may + */ +@Data +public class ParticipantVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 组id(角色id) + */ + private List groupIds; + + /** + * 候选人id(用户id) 当组id不为空时,将组内人员查出放入candidate + */ + private List candidate; + + /** + * 候选人名称(用户名称) 当组id不为空时,将组内人员查出放入candidateName + */ + private List candidateName; + + /** + * 是否认领标识 + * 当为空时默认当前任务不需要认领 + * 当为true时当前任务说明为候选模式并且有人已经认领了任务可以归还, + * 当为false时当前任务说明为候选模式该任务未认领, + */ + private Boolean claim; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ProcessDefinitionVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ProcessDefinitionVo.java new file mode 100644 index 000000000..034adbb26 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ProcessDefinitionVo.java @@ -0,0 +1,70 @@ +package org.dromara.workflow.domain.vo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 流程定义视图 + * + * @author may + */ +@Data +public class ProcessDefinitionVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 流程定义id + */ + private String id; + + /** + * 流程定义名称 + */ + private String name; + + /** + * 流程定义标识key + */ + private String key; + + /** + * 流程定义版本 + */ + private int version; + + /** + * 流程定义挂起或激活 1激活 2挂起 + */ + private int suspensionState; + + /** + * 流程xml名称 + */ + private String resourceName; + + /** + * 流程图片名称 + */ + private String diagramResourceName; + + /** + * 流程部署id + */ + private String deploymentId; + + /** + * 流程部署时间 + */ + private Date deploymentTime; + + /** + * 流程定义配置 + */ + private WfDefinitionConfigVo wfDefinitionConfigVo; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ProcessInstanceVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ProcessInstanceVo.java new file mode 100644 index 000000000..ab3e7a130 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ProcessInstanceVo.java @@ -0,0 +1,100 @@ +package org.dromara.workflow.domain.vo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * 流程实例视图 + * + * @author may + */ +@Data +public class ProcessInstanceVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 流程实例id + */ + private String id; + + /** + * 流程定义id + */ + private String processDefinitionId; + + /** + * 流程定义名称 + */ + private String processDefinitionName; + + /** + * 流程定义key + */ + private String processDefinitionKey; + + /** + * 流程定义版本 + */ + private Integer processDefinitionVersion; + + /** + * 部署id + */ + private String deploymentId; + + /** + * 业务id + */ + private String businessKey; + + /** + * 是否挂起 + */ + private Boolean isSuspended; + + /** + * 租户id + */ + private String tenantId; + + /** + * 启动时间 + */ + private Date startTime; + + /** + * 结束时间 + */ + private Date endTime; + + /** + * 启动人id + */ + private String startUserId; + + /** + * 流程状态 + */ + private String businessStatus; + + /** + * 流程状态 + */ + private String businessStatusName; + + /** + * 待办任务集合 + */ + private List taskVoList; + + /** + * 节点配置 + */ + private WfNodeConfigVo wfNodeConfigVo; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/TaskVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/TaskVo.java new file mode 100644 index 000000000..466e77690 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/TaskVo.java @@ -0,0 +1,173 @@ +package org.dromara.workflow.domain.vo; + +import lombok.Data; +import org.dromara.common.translation.annotation.Translation; +import org.dromara.common.translation.constant.TransConstant; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 任务视图 + * + * @author may + */ +@Data +public class TaskVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 任务id + */ + private String id; + + /** + * 任务名称 + */ + private String name; + + /** + * 描述 + */ + private String description; + + /** + * 优先级 + */ + private Integer priority; + + /** + * 负责此任务的人员的用户id + */ + private String owner; + + /** + * 办理人id + */ + private Long assignee; + + /** + * 办理人 + */ + @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "assignee") + private String assigneeName; + + + /** + * 流程实例id + */ + private String processInstanceId; + + /** + * 执行id + */ + private String executionId; + + /** + * 无用 + */ + private String taskDefinitionId; + + /** + * 流程定义id + */ + private String processDefinitionId; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 已办任务-创建时间 + */ + private Date startTime; + + /** + * 结束时间 + */ + private Date endTime; + + /** + * 节点id + */ + private String taskDefinitionKey; + + /** + * 任务截止日期 + */ + private Date dueDate; + + /** + * 流程类别 + */ + private String category; + + /** + * 父级任务id + */ + private String parentTaskId; + + /** + * 租户id + */ + private String tenantId; + + /** + * 认领时间 + */ + private Date claimTime; + + /** + * 流程状态 + */ + private String businessStatus; + + /** + * 流程状态 + */ + private String businessStatusName; + + /** + * 流程定义名称 + */ + private String processDefinitionName; + + /** + * 流程定义key + */ + private String processDefinitionKey; + + /** + * 流程定义版本 + */ + private Integer processDefinitionVersion; + + /** + * 参与者 + */ + private ParticipantVo participantVo; + + /** + * 是否会签 + */ + private Boolean multiInstance; + + /** + * 业务id + */ + private String businessKey; + + /** + * 流程定义配置 + */ + private WfDefinitionConfigVo wfDefinitionConfigVo; + + /** + * 节点配置 + */ + private WfNodeConfigVo wfNodeConfigVo; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/TestLeaveVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/TestLeaveVo.java new file mode 100644 index 000000000..c62a35612 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/TestLeaveVo.java @@ -0,0 +1,70 @@ +package org.dromara.workflow.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.workflow.domain.TestLeave; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 请假视图对象 test_leave + * + * @author may + * @date 2023-07-21 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = TestLeave.class) +public class TestLeaveVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 请假类型 + */ + @ExcelProperty(value = "请假类型") + private String leaveType; + + /** + * 开始时间 + */ + @ExcelProperty(value = "开始时间") + private Date startDate; + + /** + * 结束时间 + */ + @ExcelProperty(value = "结束时间") + private Date endDate; + + /** + * 请假天数 + */ + @ExcelProperty(value = "请假天数") + private Integer leaveDays; + + /** + * 备注 + */ + @ExcelProperty(value = "请假原因") + private String remark; + + /** + * 流程实例对象 + */ + private ProcessInstanceVo processInstanceVo; + + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/VariableVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/VariableVo.java new file mode 100644 index 000000000..6a26c8287 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/VariableVo.java @@ -0,0 +1,28 @@ +package org.dromara.workflow.domain.vo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 流程变量 + * + * @author may + */ +@Data +public class VariableVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 变量key + */ + private String key; + + /** + * 变量值 + */ + private String value; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfCategoryVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfCategoryVo.java new file mode 100644 index 000000000..362f64625 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfCategoryVo.java @@ -0,0 +1,58 @@ +package org.dromara.workflow.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.workflow.domain.WfCategory; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 流程分类视图对象 wf_category + * + * @author may + * @date 2023-06-27 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = WfCategory.class) +public class WfCategoryVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 分类名称 + */ + @ExcelProperty(value = "分类名称") + private String categoryName; + + /** + * 分类编码 + */ + @ExcelProperty(value = "分类编码") + private String categoryCode; + + /** + * 父级id + */ + @ExcelProperty(value = "父级id") + private Long parentId; + + /** + * 排序 + */ + @ExcelProperty(value = "排序") + private Long sortNum; + + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfCopy.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfCopy.java new file mode 100644 index 000000000..88a5a2184 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfCopy.java @@ -0,0 +1,29 @@ +package org.dromara.workflow.domain.vo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 抄送 + * + * @author may + */ +@Data +public class WfCopy implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 用户id + */ + private Long userId; + + /** + * 用户名称 + */ + private String userName; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfDefinitionConfigVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfDefinitionConfigVo.java new file mode 100644 index 000000000..9c7b0d7db --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfDefinitionConfigVo.java @@ -0,0 +1,70 @@ +package org.dromara.workflow.domain.vo; + +import org.dromara.workflow.domain.WfDefinitionConfig; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 流程定义配置视图对象 wf_definition_config + * + * @author may + * @date 2024-03-18 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = WfDefinitionConfig.class) +public class WfDefinitionConfigVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 表名 + */ + @ExcelProperty(value = "表名") + private String tableName; + + /** + * 流程定义ID + */ + @ExcelProperty(value = "流程定义ID") + private String definitionId; + + /** + * 流程KEY + */ + @ExcelProperty(value = "流程KEY") + private String processKey; + + + /** + * 流程版本 + */ + @ExcelProperty(value = "流程版本") + private Integer version; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 表单管理 + */ + private WfFormManageVo wfFormManageVo; + + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfFormManageVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfFormManageVo.java new file mode 100644 index 000000000..302df2396 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfFormManageVo.java @@ -0,0 +1,63 @@ +package org.dromara.workflow.domain.vo; + +import org.dromara.workflow.domain.WfFormManage; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 表单管理视图对象 wf_form_manage + * + * @author may + * @date 2024-03-29 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = WfFormManage.class) +public class WfFormManageVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 表单名称 + */ + @ExcelProperty(value = "表单名称") + private String formName; + + /** + * 表单类型 + */ + @ExcelProperty(value = "表单类型") + private String formType; + + /** + * 表单类型名称 + */ + private String formTypeName; + + /** + * 路由地址/表单ID + */ + @ExcelProperty(value = "路由地址/表单ID") + private String router; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfNodeConfigVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfNodeConfigVo.java new file mode 100644 index 000000000..89e9d9b3f --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfNodeConfigVo.java @@ -0,0 +1,75 @@ +package org.dromara.workflow.domain.vo; + +import org.dromara.workflow.domain.WfNodeConfig; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 节点配置视图对象 wf_node_config + * + * @author may + * @date 2024-03-30 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = WfNodeConfig.class) +public class WfNodeConfigVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 表单id + */ + @ExcelProperty(value = "表单id") + private Long formId; + + /** + * 表单类型 + */ + @ExcelProperty(value = "表单类型") + private String formType; + + /** + * 节点名称 + */ + @ExcelProperty(value = "节点名称") + private String nodeName; + + /** + * 节点id + */ + @ExcelProperty(value = "节点id") + private String nodeId; + + /** + * 流程定义id + */ + @ExcelProperty(value = "流程定义id") + private String definitionId; + + /** + * 是否为申请人节点 (0是 1否) + */ + @ExcelProperty(value = "是否为申请人节点 (0是 1否)") + private String applyUserTask; + + /** + * 表单管理 + */ + private WfFormManageVo wfFormManageVo; + + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/CustomDefaultProcessDiagramCanvas.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/CustomDefaultProcessDiagramCanvas.java new file mode 100644 index 000000000..39fd9d363 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/CustomDefaultProcessDiagramCanvas.java @@ -0,0 +1,108 @@ +package org.dromara.workflow.flowable; + +import org.flowable.bpmn.model.AssociationDirection; +import org.flowable.image.impl.DefaultProcessDiagramCanvas; + +import java.awt.*; +import java.awt.geom.Line2D; +import java.awt.geom.RoundRectangle2D; + +public class CustomDefaultProcessDiagramCanvas extends DefaultProcessDiagramCanvas { + //设置高亮线的颜色 这里我设置成绿色 + protected static Color HIGHLIGHT_SEQUENCEFLOW_COLOR = Color.GREEN; + + public CustomDefaultProcessDiagramCanvas(int width, int height, int minX, int minY, String imageType, String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) { + super(width, height, minX, minY, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader); + } + + /** + * 画线颜色设置 + */ + public void drawConnection(int[] xPoints, int[] yPoints, boolean conditional, boolean isDefault, String connectionType, + AssociationDirection associationDirection, boolean highLighted, double scaleFactor) { + + Paint originalPaint = g.getPaint(); + Stroke originalStroke = g.getStroke(); + + g.setPaint(CONNECTION_COLOR); + if (connectionType.equals("association")) { + g.setStroke(ASSOCIATION_STROKE); + } else if (highLighted) { + //设置线的颜色 + g.setPaint(HIGHLIGHT_SEQUENCEFLOW_COLOR); + g.setStroke(HIGHLIGHT_FLOW_STROKE); + } + + for (int i = 1; i < xPoints.length; i++) { + Integer sourceX = xPoints[i - 1]; + Integer sourceY = yPoints[i - 1]; + Integer targetX = xPoints[i]; + Integer targetY = yPoints[i]; + Line2D.Double line = new Line2D.Double(sourceX, sourceY, targetX, targetY); + g.draw(line); + } + + if (isDefault) { + Line2D.Double line = new Line2D.Double(xPoints[0], yPoints[0], xPoints[1], yPoints[1]); + drawDefaultSequenceFlowIndicator(line, scaleFactor); + } + + if (conditional) { + Line2D.Double line = new Line2D.Double(xPoints[0], yPoints[0], xPoints[1], yPoints[1]); + drawConditionalSequenceFlowIndicator(line, scaleFactor); + } + + if (associationDirection == AssociationDirection.ONE || associationDirection == AssociationDirection.BOTH) { + Line2D.Double line = new Line2D.Double(xPoints[xPoints.length - 2], yPoints[xPoints.length - 2], xPoints[xPoints.length - 1], yPoints[xPoints.length - 1]); + drawArrowHead(line, scaleFactor); + } + if (associationDirection == AssociationDirection.BOTH) { + Line2D.Double line = new Line2D.Double(xPoints[1], yPoints[1], xPoints[0], yPoints[0]); + drawArrowHead(line, scaleFactor); + } + g.setPaint(originalPaint); + g.setStroke(originalStroke); + } + + /** + * 高亮节点设置 + */ + public void drawHighLight(int x, int y, int width, int height) { + Paint originalPaint = g.getPaint(); + Stroke originalStroke = g.getStroke(); + //设置高亮节点的颜色 + g.setPaint(HIGHLIGHT_COLOR); + g.setStroke(THICK_TASK_BORDER_STROKE); + + RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20); + g.draw(rect); + + g.setPaint(originalPaint); + g.setStroke(originalStroke); + } + + /** + * @description: 高亮节点红色 + * @param: x + * @param: y + * @param: width + * @param: height + * @return: void + * @author: gssong + * @date: 2022/4/12 + */ + public void drawHighLightRed(int x, int y, int width, int height) { + Paint originalPaint = g.getPaint(); + Stroke originalStroke = g.getStroke(); + //设置高亮节点的颜色 + g.setPaint(Color.green); + g.setStroke(THICK_TASK_BORDER_STROKE); + + RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20); + g.draw(rect); + + g.setPaint(originalPaint); + g.setStroke(originalStroke); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/CustomDefaultProcessDiagramGenerator.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/CustomDefaultProcessDiagramGenerator.java new file mode 100644 index 000000000..e4793a26f --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/CustomDefaultProcessDiagramGenerator.java @@ -0,0 +1,1120 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.dromara.workflow.flowable; + +import org.flowable.bpmn.model.Event; +import org.flowable.bpmn.model.Process; +import org.flowable.bpmn.model.*; +import org.flowable.image.ProcessDiagramGenerator; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.InputStream; +import java.util.List; +import java.util.*; + +/** + * Class to generate an image based the diagram interchange information in a BPMN 2.0 process. + * + * @author Joram Barrez + * @author Tijs Rademakers + * @author Zheng Ji + */ +public class CustomDefaultProcessDiagramGenerator implements ProcessDiagramGenerator { + + protected Map, ActivityDrawInstruction> activityDrawInstructions = new HashMap<>(); + protected Map, ArtifactDrawInstruction> artifactDrawInstructions = new HashMap<>(); + + public CustomDefaultProcessDiagramGenerator() { + this(1.0); + } + + // The instructions on how to draw a certain construct is + // created statically and stored in a map for performance. + public CustomDefaultProcessDiagramGenerator(final double scaleFactor) { + // start event + activityDrawInstructions.put(StartEvent.class, new ActivityDrawInstruction() { + + @Override + public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); + StartEvent startEvent = (StartEvent) flowNode; + if (startEvent.getEventDefinitions() != null && !startEvent.getEventDefinitions().isEmpty()) { + EventDefinition eventDefinition = startEvent.getEventDefinitions().get(0); + if (eventDefinition instanceof TimerEventDefinition) { + processDiagramCanvas.drawTimerStartEvent(graphicInfo, scaleFactor); + } else if (eventDefinition instanceof ErrorEventDefinition) { + processDiagramCanvas.drawErrorStartEvent(graphicInfo, scaleFactor); + } else if (eventDefinition instanceof EscalationEventDefinition) { + processDiagramCanvas.drawEscalationStartEvent(graphicInfo, scaleFactor); + } else if (eventDefinition instanceof ConditionalEventDefinition) { + processDiagramCanvas.drawConditionalStartEvent(graphicInfo, scaleFactor); + } else if (eventDefinition instanceof SignalEventDefinition) { + processDiagramCanvas.drawSignalStartEvent(graphicInfo, scaleFactor); + } else if (eventDefinition instanceof MessageEventDefinition) { + processDiagramCanvas.drawMessageStartEvent(graphicInfo, scaleFactor); + } else { + processDiagramCanvas.drawNoneStartEvent(graphicInfo); + } + } else { + List eventTypeElements = startEvent.getExtensionElements().get("eventType"); + if (eventTypeElements != null && eventTypeElements.size() > 0) { + processDiagramCanvas.drawEventRegistryStartEvent(graphicInfo, scaleFactor); + + } else { + processDiagramCanvas.drawNoneStartEvent(graphicInfo); + } + } + } + }); + + // signal catch + activityDrawInstructions.put(IntermediateCatchEvent.class, new ActivityDrawInstruction() { + + @Override + public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); + IntermediateCatchEvent intermediateCatchEvent = (IntermediateCatchEvent) flowNode; + if (intermediateCatchEvent.getEventDefinitions() != null && !intermediateCatchEvent.getEventDefinitions().isEmpty()) { + + if (intermediateCatchEvent.getEventDefinitions().get(0) instanceof SignalEventDefinition) { + processDiagramCanvas.drawCatchingSignalEvent(flowNode.getName(), graphicInfo, true, scaleFactor); + } else if (intermediateCatchEvent.getEventDefinitions().get(0) instanceof TimerEventDefinition) { + processDiagramCanvas.drawCatchingTimerEvent(flowNode.getName(), graphicInfo, true, scaleFactor); + } else if (intermediateCatchEvent.getEventDefinitions().get(0) instanceof MessageEventDefinition) { + processDiagramCanvas.drawCatchingMessageEvent(flowNode.getName(), graphicInfo, true, scaleFactor); + } else if (intermediateCatchEvent.getEventDefinitions().get(0) instanceof ConditionalEventDefinition) { + processDiagramCanvas.drawCatchingConditionalEvent(flowNode.getName(), graphicInfo, true, scaleFactor); + } + } + } + }); + + // signal throw + activityDrawInstructions.put(ThrowEvent.class, new ActivityDrawInstruction() { + + @Override + public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); + ThrowEvent throwEvent = (ThrowEvent) flowNode; + if (throwEvent.getEventDefinitions() != null && !throwEvent.getEventDefinitions().isEmpty()) { + if (throwEvent.getEventDefinitions().get(0) instanceof SignalEventDefinition) { + processDiagramCanvas.drawThrowingSignalEvent(graphicInfo, scaleFactor); + } else if (throwEvent.getEventDefinitions().get(0) instanceof EscalationEventDefinition) { + processDiagramCanvas.drawThrowingEscalationEvent(graphicInfo, scaleFactor); + } else if (throwEvent.getEventDefinitions().get(0) instanceof CompensateEventDefinition) { + processDiagramCanvas.drawThrowingCompensateEvent(graphicInfo, scaleFactor); + } else { + processDiagramCanvas.drawThrowingNoneEvent(graphicInfo, scaleFactor); + } + } else { + processDiagramCanvas.drawThrowingNoneEvent(graphicInfo, scaleFactor); + } + } + }); + + // end event + activityDrawInstructions.put(EndEvent.class, new ActivityDrawInstruction() { + + @Override + public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); + EndEvent endEvent = (EndEvent) flowNode; + if (endEvent.getEventDefinitions() != null && !endEvent.getEventDefinitions().isEmpty()) { + if (endEvent.getEventDefinitions().get(0) instanceof ErrorEventDefinition) { + processDiagramCanvas.drawErrorEndEvent(flowNode.getName(), graphicInfo, scaleFactor); + } else if (endEvent.getEventDefinitions().get(0) instanceof EscalationEventDefinition) { + processDiagramCanvas.drawEscalationEndEvent(flowNode.getName(), graphicInfo, scaleFactor); + } else { + processDiagramCanvas.drawNoneEndEvent(graphicInfo, scaleFactor); + } + } else { + processDiagramCanvas.drawNoneEndEvent(graphicInfo, scaleFactor); + } + } + }); + + // task + activityDrawInstructions.put(Task.class, new ActivityDrawInstruction() { + + @Override + public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); + processDiagramCanvas.drawTask(flowNode.getName(), graphicInfo, scaleFactor); + } + }); + + // user task + activityDrawInstructions.put(UserTask.class, new ActivityDrawInstruction() { + + @Override + public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); + processDiagramCanvas.drawUserTask(flowNode.getName(), graphicInfo, scaleFactor); + } + }); + + // script task + activityDrawInstructions.put(ScriptTask.class, new ActivityDrawInstruction() { + + @Override + public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); + processDiagramCanvas.drawScriptTask(flowNode.getName(), graphicInfo, scaleFactor); + } + }); + + // service task + activityDrawInstructions.put(ServiceTask.class, new ActivityDrawInstruction() { + + @Override + public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); + ServiceTask serviceTask = (ServiceTask) flowNode; + if ("camel".equalsIgnoreCase(serviceTask.getType())) { + processDiagramCanvas.drawCamelTask(serviceTask.getName(), graphicInfo, scaleFactor); + }else if (ServiceTask.HTTP_TASK.equalsIgnoreCase(serviceTask.getType())) { + processDiagramCanvas.drawHttpTask(serviceTask.getName(), graphicInfo, scaleFactor); + } else if (ServiceTask.DMN_TASK.equalsIgnoreCase(serviceTask.getType())) { + processDiagramCanvas.drawDMNTask(serviceTask.getName(), graphicInfo, scaleFactor); + } else if (ServiceTask.SHELL_TASK.equalsIgnoreCase(serviceTask.getType())) { + processDiagramCanvas.drawShellTask(serviceTask.getName(), graphicInfo, scaleFactor); + } else { + processDiagramCanvas.drawServiceTask(serviceTask.getName(), graphicInfo, scaleFactor); + } + } + }); + + // http service task + activityDrawInstructions.put(HttpServiceTask.class, new ActivityDrawInstruction() { + + @Override + public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); + processDiagramCanvas.drawHttpTask(flowNode.getName(), graphicInfo, scaleFactor); + } + }); + + // receive task + activityDrawInstructions.put(ReceiveTask.class, new ActivityDrawInstruction() { + + @Override + public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); + processDiagramCanvas.drawReceiveTask(flowNode.getName(), graphicInfo, scaleFactor); + } + }); + + // send task + activityDrawInstructions.put(SendTask.class, new ActivityDrawInstruction() { + + @Override + public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); + processDiagramCanvas.drawSendTask(flowNode.getName(), graphicInfo, scaleFactor); + } + }); + + // manual task + activityDrawInstructions.put(ManualTask.class, new ActivityDrawInstruction() { + + @Override + public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); + processDiagramCanvas.drawManualTask(flowNode.getName(), graphicInfo, scaleFactor); + } + }); + + // send event service task + activityDrawInstructions.put(SendEventServiceTask.class, new ActivityDrawInstruction() { + + @Override + public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); + processDiagramCanvas.drawSendEventServiceTask(flowNode.getName(), graphicInfo, scaleFactor); + } + }); + + // external worker service task + activityDrawInstructions.put(ExternalWorkerServiceTask.class, new ActivityDrawInstruction() { + + @Override + public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); + ServiceTask serviceTask = (ServiceTask) flowNode; + processDiagramCanvas.drawServiceTask(serviceTask.getName(), graphicInfo, scaleFactor); + } + }); + + // case service task + activityDrawInstructions.put(CaseServiceTask.class, new ActivityDrawInstruction() { + + @Override + public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); + processDiagramCanvas.drawCaseServiceTask(flowNode.getName(), graphicInfo, scaleFactor); + } + }); + + // businessRuleTask task + activityDrawInstructions.put(BusinessRuleTask.class, new ActivityDrawInstruction() { + + @Override + public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); + processDiagramCanvas.drawBusinessRuleTask(flowNode.getName(), graphicInfo, scaleFactor); + } + }); + + // exclusive gateway + activityDrawInstructions.put(ExclusiveGateway.class, new ActivityDrawInstruction() { + + @Override + public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); + processDiagramCanvas.drawExclusiveGateway(graphicInfo, scaleFactor); + } + }); + + // inclusive gateway + activityDrawInstructions.put(InclusiveGateway.class, new ActivityDrawInstruction() { + + @Override + public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); + processDiagramCanvas.drawInclusiveGateway(graphicInfo, scaleFactor); + } + }); + + // parallel gateway + activityDrawInstructions.put(ParallelGateway.class, new ActivityDrawInstruction() { + + @Override + public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); + processDiagramCanvas.drawParallelGateway(graphicInfo, scaleFactor); + } + }); + + // event based gateway + activityDrawInstructions.put(EventGateway.class, new ActivityDrawInstruction() { + + @Override + public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); + processDiagramCanvas.drawEventBasedGateway(graphicInfo, scaleFactor); + } + }); + + // Boundary timer + activityDrawInstructions.put(BoundaryEvent.class, new ActivityDrawInstruction() { + + @Override + public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); + BoundaryEvent boundaryEvent = (BoundaryEvent) flowNode; + if (boundaryEvent.getEventDefinitions() != null && !boundaryEvent.getEventDefinitions().isEmpty()) { + EventDefinition eventDefinition = boundaryEvent.getEventDefinitions().get(0); + if (eventDefinition instanceof TimerEventDefinition) { + processDiagramCanvas.drawCatchingTimerEvent(flowNode.getName(), graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor); + + } else if (eventDefinition instanceof ConditionalEventDefinition) { + processDiagramCanvas.drawCatchingConditionalEvent(graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor); + + } else if (eventDefinition instanceof ErrorEventDefinition) { + processDiagramCanvas.drawCatchingErrorEvent(graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor); + + } else if (eventDefinition instanceof EscalationEventDefinition) { + processDiagramCanvas.drawCatchingEscalationEvent(graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor); + + } else if (eventDefinition instanceof SignalEventDefinition) { + processDiagramCanvas.drawCatchingSignalEvent(flowNode.getName(), graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor); + + } else if (eventDefinition instanceof MessageEventDefinition) { + processDiagramCanvas.drawCatchingMessageEvent(flowNode.getName(), graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor); + + } else if (eventDefinition instanceof CompensateEventDefinition) { + processDiagramCanvas.drawCatchingCompensateEvent(graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor); + } + + } else { + List eventTypeElements = boundaryEvent.getExtensionElements().get("eventType"); + if (eventTypeElements != null && eventTypeElements.size() > 0) { + processDiagramCanvas.drawCatchingEventRegistryEvent(flowNode.getName(), graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor); + } + } + } + }); + + // subprocess + activityDrawInstructions.put(SubProcess.class, new ActivityDrawInstruction() { + + @Override + public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); + if (graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) { + processDiagramCanvas.drawCollapsedSubProcess(flowNode.getName(), graphicInfo, false, scaleFactor); + } else { + processDiagramCanvas.drawExpandedSubProcess(flowNode.getName(), graphicInfo, false, scaleFactor); + } + } + }); + + // transaction + activityDrawInstructions.put(Transaction.class, new ActivityDrawInstruction() { + + @Override + public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); + if (graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) { + processDiagramCanvas.drawCollapsedSubProcess(flowNode.getName(), graphicInfo, false, scaleFactor); + } else { + processDiagramCanvas.drawExpandedTransaction(flowNode.getName(), graphicInfo, scaleFactor); + } + } + }); + + // Event subprocess + activityDrawInstructions.put(EventSubProcess.class, new ActivityDrawInstruction() { + + @Override + public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); + if (graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) { + processDiagramCanvas.drawCollapsedSubProcess(flowNode.getName(), graphicInfo, true, scaleFactor); + } else { + processDiagramCanvas.drawExpandedSubProcess(flowNode.getName(), graphicInfo, true, scaleFactor); + } + } + }); + + // Adhoc subprocess + activityDrawInstructions.put(AdhocSubProcess.class, new ActivityDrawInstruction() { + + @Override + public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); + if (graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) { + processDiagramCanvas.drawCollapsedSubProcess(flowNode.getName(), graphicInfo, false, scaleFactor); + } else { + processDiagramCanvas.drawExpandedSubProcess(flowNode.getName(), graphicInfo, false, scaleFactor); + } + } + }); + + // call activity + activityDrawInstructions.put(CallActivity.class, new ActivityDrawInstruction() { + + @Override + public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); + processDiagramCanvas.drawCollapsedCallActivity(flowNode.getName(), graphicInfo, scaleFactor); + } + }); + + // text annotation + artifactDrawInstructions.put(TextAnnotation.class, new ArtifactDrawInstruction() { + + @Override + public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, Artifact artifact) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(artifact.getId()); + TextAnnotation textAnnotation = (TextAnnotation) artifact; + processDiagramCanvas.drawTextAnnotation(textAnnotation.getText(), graphicInfo, scaleFactor); + } + }); + + // association + artifactDrawInstructions.put(Association.class, new ArtifactDrawInstruction() { + + @Override + public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, Artifact artifact) { + Association association = (Association) artifact; + String sourceRef = association.getSourceRef(); + String targetRef = association.getTargetRef(); + + // source and target can be instance of FlowElement or Artifact + BaseElement sourceElement = bpmnModel.getFlowElement(sourceRef); + BaseElement targetElement = bpmnModel.getFlowElement(targetRef); + if (sourceElement == null) { + sourceElement = bpmnModel.getArtifact(sourceRef); + } + if (targetElement == null) { + targetElement = bpmnModel.getArtifact(targetRef); + } + List graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(artifact.getId()); + graphicInfoList = connectionPerfectionizer(processDiagramCanvas, bpmnModel, sourceElement, targetElement, graphicInfoList); + int[] xPoints = new int[graphicInfoList.size()]; + int[] yPoints = new int[graphicInfoList.size()]; + for (int i = 1; i < graphicInfoList.size(); i++) { + GraphicInfo graphicInfo = graphicInfoList.get(i); + GraphicInfo previousGraphicInfo = graphicInfoList.get(i - 1); + + if (i == 1) { + xPoints[0] = (int) previousGraphicInfo.getX(); + yPoints[0] = (int) previousGraphicInfo.getY(); + } + xPoints[i] = (int) graphicInfo.getX(); + yPoints[i] = (int) graphicInfo.getY(); + } + + AssociationDirection associationDirection = association.getAssociationDirection(); + processDiagramCanvas.drawAssociation(xPoints, yPoints, associationDirection, false, scaleFactor); + } + }); + } + + @Override + public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List highLightedActivities, List highLightedFlows, + String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) { + + return generateProcessDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows, + activityFontName, labelFontName, annotationFontName, customClassLoader, scaleFactor, drawSequenceFlowNameWithNoLabelDI).generateImage(imageType); + } + + @Override + public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List highLightedActivities, List highLightedFlows, boolean drawSequenceFlowNameWithNoLabelDI) { + return generateDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows, null, null, null, null, 1.0, drawSequenceFlowNameWithNoLabelDI); + } + + @Override + public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, + List highLightedActivities, List highLightedFlows, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) { + return generateDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows, null, null, null, null, scaleFactor, drawSequenceFlowNameWithNoLabelDI); + } + + @Override + public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List highLightedActivities, boolean drawSequenceFlowNameWithNoLabelDI) { + return generateDiagram(bpmnModel, imageType, highLightedActivities, Collections.emptyList(), drawSequenceFlowNameWithNoLabelDI); + } + + @Override + public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List highLightedActivities, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) { + return generateDiagram(bpmnModel, imageType, highLightedActivities, Collections.emptyList(), scaleFactor, drawSequenceFlowNameWithNoLabelDI); + } + + @Override + public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, String activityFontName, + String labelFontName, String annotationFontName, ClassLoader customClassLoader, boolean drawSequenceFlowNameWithNoLabelDI) { + + return generateDiagram(bpmnModel, imageType, Collections.emptyList(), Collections.emptyList(), + activityFontName, labelFontName, annotationFontName, customClassLoader, 1.0, drawSequenceFlowNameWithNoLabelDI); + } + + @Override + public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, String activityFontName, + String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) { + + return generateDiagram(bpmnModel, imageType, Collections.emptyList(), Collections.emptyList(), + activityFontName, labelFontName, annotationFontName, customClassLoader, scaleFactor, drawSequenceFlowNameWithNoLabelDI); + } + + @Override + public InputStream generatePngDiagram(BpmnModel bpmnModel, boolean drawSequenceFlowNameWithNoLabelDI) { + return generatePngDiagram(bpmnModel, 1.0, drawSequenceFlowNameWithNoLabelDI); + } + + @Override + public InputStream generatePngDiagram(BpmnModel bpmnModel, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) { + return generateDiagram(bpmnModel, "png", Collections.emptyList(), Collections.emptyList(), scaleFactor, drawSequenceFlowNameWithNoLabelDI); + } + + @Override + public InputStream generateJpgDiagram(BpmnModel bpmnModel) { + return generateJpgDiagram(bpmnModel, 1.0, false); + } + + @Override + public InputStream generateJpgDiagram(BpmnModel bpmnModel, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) { + return generateDiagram(bpmnModel, "jpg", Collections.emptyList(), Collections.emptyList(), drawSequenceFlowNameWithNoLabelDI); + } + + public BufferedImage generateImage(BpmnModel bpmnModel, String imageType, List highLightedActivities, List highLightedFlows, + String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) { + + return generateProcessDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows, + activityFontName, labelFontName, annotationFontName, customClassLoader, scaleFactor, drawSequenceFlowNameWithNoLabelDI).generateBufferedImage(imageType); + } + + public BufferedImage generateImage(BpmnModel bpmnModel, String imageType, + List highLightedActivities, List highLightedFlows, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) { + + return generateImage(bpmnModel, imageType, highLightedActivities, highLightedFlows, null, null, null, null, scaleFactor, drawSequenceFlowNameWithNoLabelDI); + } + + @Override + public BufferedImage generatePngImage(BpmnModel bpmnModel, double scaleFactor) { + return generateImage(bpmnModel, "png", Collections.emptyList(), Collections.emptyList(), scaleFactor, false); + } + + protected CustomDefaultProcessDiagramCanvas generateProcessDiagram(BpmnModel bpmnModel, String imageType, + List highLightedActivities, List highLightedFlows, + String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) { + + prepareBpmnModel(bpmnModel); + + CustomDefaultProcessDiagramCanvas processDiagramCanvas = initProcessDiagramCanvas(bpmnModel, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader); + + // Draw pool shape, if process is participant in collaboration + for (Pool pool : bpmnModel.getPools()) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(pool.getId()); + processDiagramCanvas.drawPoolOrLane(pool.getName(), graphicInfo, scaleFactor); + } + + // Draw lanes + for (Process process : bpmnModel.getProcesses()) { + for (Lane lane : process.getLanes()) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(lane.getId()); + processDiagramCanvas.drawPoolOrLane(lane.getName(), graphicInfo, scaleFactor); + } + } + + // Draw activities and their sequence-flows + for (Process process : bpmnModel.getProcesses()) { + for (FlowNode flowNode : process.findFlowElementsOfType(FlowNode.class)) { + if (!isPartOfCollapsedSubProcess(flowNode, bpmnModel)) { + drawActivity(processDiagramCanvas, bpmnModel, flowNode, highLightedActivities, highLightedFlows, scaleFactor, drawSequenceFlowNameWithNoLabelDI); + } + } + } + + // Draw artifacts + for (Process process : bpmnModel.getProcesses()) { + + for (Artifact artifact : process.getArtifacts()) { + drawArtifact(processDiagramCanvas, bpmnModel, artifact); + } + + List subProcesses = process.findFlowElementsOfType(SubProcess.class, true); + if (subProcesses != null) { + for (SubProcess subProcess : subProcesses) { + + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(subProcess.getId()); + if (graphicInfo != null && graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) { + continue; + } + + if (!isPartOfCollapsedSubProcess(subProcess, bpmnModel)) { + for (Artifact subProcessArtifact : subProcess.getArtifacts()) { + drawArtifact(processDiagramCanvas, bpmnModel, subProcessArtifact); + } + } + } + } + } + + return processDiagramCanvas; + } + + protected void prepareBpmnModel(BpmnModel bpmnModel) { + + // Need to make sure all elements have positive x and y. + // Check all graphicInfo and update the elements accordingly + + List allGraphicInfos = new ArrayList<>(); + if (bpmnModel.getLocationMap() != null) { + allGraphicInfos.addAll(bpmnModel.getLocationMap().values()); + } + if (bpmnModel.getLabelLocationMap() != null) { + allGraphicInfos.addAll(bpmnModel.getLabelLocationMap().values()); + } + if (bpmnModel.getFlowLocationMap() != null) { + for (List flowGraphicInfos : bpmnModel.getFlowLocationMap().values()) { + allGraphicInfos.addAll(flowGraphicInfos); + } + } + + if (allGraphicInfos.size() > 0) { + + boolean needsTranslationX = false; + boolean needsTranslationY = false; + + double lowestX = 0.0; + double lowestY = 0.0; + + // Collect lowest x and y + for (GraphicInfo graphicInfo : allGraphicInfos) { + + double x = graphicInfo.getX(); + double y = graphicInfo.getY(); + + if (x < lowestX) { + needsTranslationX = true; + lowestX = x; + } + if (y < lowestY) { + needsTranslationY = true; + lowestY = y; + } + + } + + // Update all graphicInfo objects + if (needsTranslationX || needsTranslationY) { + + double translationX = Math.abs(lowestX); + double translationY = Math.abs(lowestY); + + for (GraphicInfo graphicInfo : allGraphicInfos) { + if (needsTranslationX) { + graphicInfo.setX(graphicInfo.getX() + translationX); + } + if (needsTranslationY) { + graphicInfo.setY(graphicInfo.getY() + translationY); + } + } + } + + } + + } + + protected void drawActivity(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, + FlowNode flowNode, List highLightedActivities, List highLightedFlows, double scaleFactor, Boolean drawSequenceFlowNameWithNoLabelDI) { + + ActivityDrawInstruction drawInstruction = activityDrawInstructions.get(flowNode.getClass()); + if (drawInstruction != null) { + + drawInstruction.draw(processDiagramCanvas, bpmnModel, flowNode); + + // Gather info on the multi instance marker + boolean multiInstanceSequential = false; + boolean multiInstanceParallel = false; + boolean collapsed = false; + if (flowNode instanceof Activity) { + Activity activity = (Activity) flowNode; + MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics = activity.getLoopCharacteristics(); + if (multiInstanceLoopCharacteristics != null) { + multiInstanceSequential = multiInstanceLoopCharacteristics.isSequential(); + multiInstanceParallel = !multiInstanceSequential; + } + } + + // Gather info on the collapsed marker + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); + if (flowNode instanceof SubProcess) { + collapsed = graphicInfo.getExpanded() != null && !graphicInfo.getExpanded(); + } else if (flowNode instanceof CallActivity) { + collapsed = true; + } + + if (scaleFactor == 1.0) { + // Actually draw the markers + processDiagramCanvas.drawActivityMarkers((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight(), + multiInstanceSequential, multiInstanceParallel, collapsed); + } + + // Draw highlighted activities + if (highLightedActivities.contains(flowNode.getId())) { + drawHighLightRed(processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId())); + } else if (highLightedActivities.contains(Color.RED.toString() + flowNode.getId())) { + drawHighLight(processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId())); + } + + } else if (flowNode instanceof Task) { + activityDrawInstructions.get(Task.class).draw(processDiagramCanvas, bpmnModel, flowNode); + + if (highLightedActivities.contains(flowNode.getId())) { + drawHighLightRed(processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId())); + } else if (highLightedActivities.contains(Color.RED.toString() + flowNode.getId())) { + drawHighLight(processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId())); + } + } + + // Outgoing transitions of activity + for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) { + boolean highLighted = (highLightedFlows.contains(sequenceFlow.getId())); + String defaultFlow = null; + if (flowNode instanceof Activity) { + defaultFlow = ((Activity) flowNode).getDefaultFlow(); + } else if (flowNode instanceof Gateway) { + defaultFlow = ((Gateway) flowNode).getDefaultFlow(); + } + + boolean isDefault = false; + if (defaultFlow != null && defaultFlow.equalsIgnoreCase(sequenceFlow.getId())) { + isDefault = true; + } + boolean drawConditionalIndicator = sequenceFlow.getConditionExpression() != null && sequenceFlow.getConditionExpression().trim().length() > 0 && !(flowNode instanceof Gateway); + + String sourceRef = sequenceFlow.getSourceRef(); + String targetRef = sequenceFlow.getTargetRef(); + FlowElement sourceElement = bpmnModel.getFlowElement(sourceRef); + FlowElement targetElement = bpmnModel.getFlowElement(targetRef); + List graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(sequenceFlow.getId()); + if (graphicInfoList != null && graphicInfoList.size() > 0) { + graphicInfoList = connectionPerfectionizer(processDiagramCanvas, bpmnModel, sourceElement, targetElement, graphicInfoList); + int[] xPoints = new int[graphicInfoList.size()]; + int[] yPoints = new int[graphicInfoList.size()]; + + for (int i = 1; i < graphicInfoList.size(); i++) { + GraphicInfo graphicInfo = graphicInfoList.get(i); + GraphicInfo previousGraphicInfo = graphicInfoList.get(i - 1); + + if (i == 1) { + xPoints[0] = (int) previousGraphicInfo.getX(); + yPoints[0] = (int) previousGraphicInfo.getY(); + } + xPoints[i] = (int) graphicInfo.getX(); + yPoints[i] = (int) graphicInfo.getY(); + + } + + processDiagramCanvas.drawSequenceflow(xPoints, yPoints, drawConditionalIndicator, isDefault, highLighted, scaleFactor); + + // Draw sequenceflow label + GraphicInfo labelGraphicInfo = bpmnModel.getLabelGraphicInfo(sequenceFlow.getId()); + if (labelGraphicInfo != null) { + processDiagramCanvas.drawLabel(sequenceFlow.getName(), labelGraphicInfo, false); + } else { + if (drawSequenceFlowNameWithNoLabelDI) { + GraphicInfo lineCenter = getLineCenter(graphicInfoList); + processDiagramCanvas.drawLabel(sequenceFlow.getName(), lineCenter, false); + } + + } + } + } + + // Nested elements + if (flowNode instanceof FlowElementsContainer) { + for (FlowElement nestedFlowElement : ((FlowElementsContainer) flowNode).getFlowElements()) { + if (nestedFlowElement instanceof FlowNode && !isPartOfCollapsedSubProcess(nestedFlowElement, bpmnModel)) { + drawActivity(processDiagramCanvas, bpmnModel, (FlowNode) nestedFlowElement, + highLightedActivities, highLightedFlows, scaleFactor, drawSequenceFlowNameWithNoLabelDI); + } + } + } + } + + /** + * This method makes coordinates of connection flow better. + * + * @param processDiagramCanvas + * @param bpmnModel + * @param sourceElement + * @param targetElement + * @param graphicInfoList + * @return + */ + protected static List connectionPerfectionizer(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, BaseElement sourceElement, BaseElement targetElement, List graphicInfoList) { + GraphicInfo sourceGraphicInfo = bpmnModel.getGraphicInfo(sourceElement.getId()); + GraphicInfo targetGraphicInfo = bpmnModel.getGraphicInfo(targetElement.getId()); + + CustomDefaultProcessDiagramCanvas.SHAPE_TYPE sourceShapeType = getShapeType(sourceElement); + CustomDefaultProcessDiagramCanvas.SHAPE_TYPE targetShapeType = getShapeType(targetElement); + + return processDiagramCanvas.connectionPerfectionizer(sourceShapeType, targetShapeType, sourceGraphicInfo, targetGraphicInfo, graphicInfoList); + } + + /** + * This method returns shape type of base element.
+ * Each element can be presented as rectangle, rhombus, or ellipse. + * + * @param baseElement + * @return CustomDefaultProcessDiagramCanvas.SHAPE_TYPE + */ + protected static CustomDefaultProcessDiagramCanvas.SHAPE_TYPE getShapeType(BaseElement baseElement) { + if (baseElement instanceof Task || baseElement instanceof Activity || baseElement instanceof TextAnnotation) { + return CustomDefaultProcessDiagramCanvas.SHAPE_TYPE.Rectangle; + } else if (baseElement instanceof Gateway) { + return CustomDefaultProcessDiagramCanvas.SHAPE_TYPE.Rhombus; + } else if (baseElement instanceof Event) { + return CustomDefaultProcessDiagramCanvas.SHAPE_TYPE.Ellipse; + } else { + // unknown source element, just do not correct coordinates + } + return null; + } + + protected static GraphicInfo getLineCenter(List graphicInfoList) { + GraphicInfo gi = new GraphicInfo(); + + int[] xPoints = new int[graphicInfoList.size()]; + int[] yPoints = new int[graphicInfoList.size()]; + + double length = 0; + double[] lengths = new double[graphicInfoList.size()]; + lengths[0] = 0; + double m; + for (int i = 1; i < graphicInfoList.size(); i++) { + GraphicInfo graphicInfo = graphicInfoList.get(i); + GraphicInfo previousGraphicInfo = graphicInfoList.get(i - 1); + + if (i == 1) { + xPoints[0] = (int) previousGraphicInfo.getX(); + yPoints[0] = (int) previousGraphicInfo.getY(); + } + xPoints[i] = (int) graphicInfo.getX(); + yPoints[i] = (int) graphicInfo.getY(); + + length += Math.sqrt( + Math.pow((int) graphicInfo.getX() - (int) previousGraphicInfo.getX(), 2) + + Math.pow((int) graphicInfo.getY() - (int) previousGraphicInfo.getY(), 2)); + lengths[i] = length; + } + m = length / 2; + int p1 = 0; + int p2 = 1; + for (int i = 1; i < lengths.length; i++) { + double len = lengths[i]; + p1 = i - 1; + p2 = i; + if (len > m) { + break; + } + } + + GraphicInfo graphicInfo1 = graphicInfoList.get(p1); + GraphicInfo graphicInfo2 = graphicInfoList.get(p2); + + double AB = (int) graphicInfo2.getX() - (int) graphicInfo1.getX(); + double OA = (int) graphicInfo2.getY() - (int) graphicInfo1.getY(); + double OB = lengths[p2] - lengths[p1]; + double ob = m - lengths[p1]; + double ab = AB * ob / OB; + double oa = OA * ob / OB; + + double mx = graphicInfo1.getX() + ab; + double my = graphicInfo1.getY() + oa; + + gi.setX(mx); + gi.setY(my); + return gi; + } + + protected void drawArtifact(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, Artifact artifact) { + + ArtifactDrawInstruction drawInstruction = artifactDrawInstructions.get(artifact.getClass()); + if (drawInstruction != null) { + drawInstruction.draw(processDiagramCanvas, bpmnModel, artifact); + } + } + + private static void drawHighLight(CustomDefaultProcessDiagramCanvas processDiagramCanvas, GraphicInfo graphicInfo) { + processDiagramCanvas.drawHighLight((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight()); + + } + + private static void drawHighLightRed(CustomDefaultProcessDiagramCanvas processDiagramCanvas, GraphicInfo graphicInfo) { + processDiagramCanvas.drawHighLightRed((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight()); + + } + + protected static CustomDefaultProcessDiagramCanvas initProcessDiagramCanvas(BpmnModel bpmnModel, String imageType, + String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) { + + // We need to calculate maximum values to know how big the image will be in its entirety + double minX = Double.MAX_VALUE; + double maxX = 0; + double minY = Double.MAX_VALUE; + double maxY = 0; + + for (Pool pool : bpmnModel.getPools()) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(pool.getId()); + minX = graphicInfo.getX(); + maxX = graphicInfo.getX() + graphicInfo.getWidth(); + minY = graphicInfo.getY(); + maxY = graphicInfo.getY() + graphicInfo.getHeight(); + } + + List flowNodes = gatherAllFlowNodes(bpmnModel); + for (FlowNode flowNode : flowNodes) { + + GraphicInfo flowNodeGraphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); + + // width + if (flowNodeGraphicInfo.getX() + flowNodeGraphicInfo.getWidth() > maxX) { + maxX = flowNodeGraphicInfo.getX() + flowNodeGraphicInfo.getWidth(); + } + if (flowNodeGraphicInfo.getX() < minX) { + minX = flowNodeGraphicInfo.getX(); + } + // height + if (flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight() > maxY) { + maxY = flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight(); + } + if (flowNodeGraphicInfo.getY() < minY) { + minY = flowNodeGraphicInfo.getY(); + } + + for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) { + List graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(sequenceFlow.getId()); + if (graphicInfoList != null) { + for (GraphicInfo graphicInfo : graphicInfoList) { + // width + if (graphicInfo.getX() > maxX) { + maxX = graphicInfo.getX(); + } + if (graphicInfo.getX() < minX) { + minX = graphicInfo.getX(); + } + // height + if (graphicInfo.getY() > maxY) { + maxY = graphicInfo.getY(); + } + if (graphicInfo.getY() < minY) { + minY = graphicInfo.getY(); + } + } + } + } + } + + List artifacts = gatherAllArtifacts(bpmnModel); + for (Artifact artifact : artifacts) { + + GraphicInfo artifactGraphicInfo = bpmnModel.getGraphicInfo(artifact.getId()); + + if (artifactGraphicInfo != null) { + // width + if (artifactGraphicInfo.getX() + artifactGraphicInfo.getWidth() > maxX) { + maxX = artifactGraphicInfo.getX() + artifactGraphicInfo.getWidth(); + } + if (artifactGraphicInfo.getX() < minX) { + minX = artifactGraphicInfo.getX(); + } + // height + if (artifactGraphicInfo.getY() + artifactGraphicInfo.getHeight() > maxY) { + maxY = artifactGraphicInfo.getY() + artifactGraphicInfo.getHeight(); + } + if (artifactGraphicInfo.getY() < minY) { + minY = artifactGraphicInfo.getY(); + } + } + + List graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(artifact.getId()); + if (graphicInfoList != null) { + for (GraphicInfo graphicInfo : graphicInfoList) { + // width + if (graphicInfo.getX() > maxX) { + maxX = graphicInfo.getX(); + } + if (graphicInfo.getX() < minX) { + minX = graphicInfo.getX(); + } + // height + if (graphicInfo.getY() > maxY) { + maxY = graphicInfo.getY(); + } + if (graphicInfo.getY() < minY) { + minY = graphicInfo.getY(); + } + } + } + } + + int nrOfLanes = 0; + for (Process process : bpmnModel.getProcesses()) { + for (Lane l : process.getLanes()) { + + nrOfLanes++; + + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(l.getId()); + // // width + if (graphicInfo.getX() + graphicInfo.getWidth() > maxX) { + maxX = graphicInfo.getX() + graphicInfo.getWidth(); + } + if (graphicInfo.getX() < minX) { + minX = graphicInfo.getX(); + } + // height + if (graphicInfo.getY() + graphicInfo.getHeight() > maxY) { + maxY = graphicInfo.getY() + graphicInfo.getHeight(); + } + if (graphicInfo.getY() < minY) { + minY = graphicInfo.getY(); + } + } + } + + // Special case, see https://activiti.atlassian.net/browse/ACT-1431 + if (flowNodes.isEmpty() && bpmnModel.getPools().isEmpty() && nrOfLanes == 0) { + // Nothing to show + minX = 0; + minY = 0; + } + + return new CustomDefaultProcessDiagramCanvas((int) maxX + 10, (int) maxY + 10, (int) minX, (int) minY, + imageType, activityFontName, labelFontName, annotationFontName, customClassLoader); + } + + protected static List gatherAllArtifacts(BpmnModel bpmnModel) { + List artifacts = new ArrayList<>(); + for (Process process : bpmnModel.getProcesses()) { + artifacts.addAll(process.getArtifacts()); + } + return artifacts; + } + + protected static List gatherAllFlowNodes(BpmnModel bpmnModel) { + List flowNodes = new ArrayList<>(); + for (Process process : bpmnModel.getProcesses()) { + flowNodes.addAll(gatherAllFlowNodes(process)); + } + return flowNodes; + } + + protected static List gatherAllFlowNodes(FlowElementsContainer flowElementsContainer) { + List flowNodes = new ArrayList<>(); + for (FlowElement flowElement : flowElementsContainer.getFlowElements()) { + if (flowElement instanceof FlowNode) { + flowNodes.add((FlowNode) flowElement); + } + if (flowElement instanceof FlowElementsContainer) { + flowNodes.addAll(gatherAllFlowNodes((FlowElementsContainer) flowElement)); + } + } + return flowNodes; + } + + protected boolean isPartOfCollapsedSubProcess(FlowElement flowElement, BpmnModel model) { + SubProcess subProcess = flowElement.getSubProcess(); + if (subProcess != null) { + GraphicInfo graphicInfo = model.getGraphicInfo(subProcess.getId()); + if (graphicInfo != null && graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) { + return true; + } + + return isPartOfCollapsedSubProcess(subProcess, model); + } + + return false; + } + + public Map, ActivityDrawInstruction> getActivityDrawInstructions() { + return activityDrawInstructions; + } + + public void setActivityDrawInstructions( + Map, ActivityDrawInstruction> activityDrawInstructions) { + this.activityDrawInstructions = activityDrawInstructions; + } + + public Map, ArtifactDrawInstruction> getArtifactDrawInstructions() { + return artifactDrawInstructions; + } + + public void setArtifactDrawInstructions( + Map, ArtifactDrawInstruction> artifactDrawInstructions) { + this.artifactDrawInstructions = artifactDrawInstructions; + } + + protected interface ActivityDrawInstruction { + void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode); + } + + protected interface ArtifactDrawInstruction { + void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, Artifact artifact); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/AddSequenceMultiInstanceCmd.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/AddSequenceMultiInstanceCmd.java new file mode 100644 index 000000000..3cdfcf415 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/AddSequenceMultiInstanceCmd.java @@ -0,0 +1,61 @@ +package org.dromara.workflow.flowable.cmd; + +import cn.hutool.core.collection.CollUtil; +import org.flowable.common.engine.impl.interceptor.Command; +import org.flowable.common.engine.impl.interceptor.CommandContext; +import org.flowable.engine.impl.persistence.entity.ExecutionEntity; +import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager; +import org.flowable.engine.impl.util.CommandContextUtil; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.dromara.workflow.common.constant.FlowConstant.NUMBER_OF_INSTANCES; + +/** + * 串行加签 + * + * @author may + */ +public class AddSequenceMultiInstanceCmd implements Command { + + /** + * 执行id + */ + private final String executionId; + + /** + * 会签人员集合KEY + */ + private final String assigneeList; + + /** + * 加签人员 + */ + private final List assignees; + + public AddSequenceMultiInstanceCmd(String executionId, String assigneeList, List assignees) { + this.executionId = executionId; + this.assigneeList = assigneeList; + this.assignees = assignees; + } + + @Override + public Void execute(CommandContext commandContext) { + ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager(); + ExecutionEntity entity = executionEntityManager.findById(executionId); + // 多实例任务总数加 assignees.size() + if (entity.getVariable(NUMBER_OF_INSTANCES) instanceof Integer nrOfInstances) { + entity.setVariable(NUMBER_OF_INSTANCES, nrOfInstances + assignees.size()); + } + // 设置流程变量 + if (entity.getVariable(assigneeList) instanceof List userIds) { + CollUtil.addAll(userIds, assignees); + Map variables = new HashMap<>(16); + variables.put(assigneeList, userIds); + entity.setVariables(variables); + } + return null; + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/AttachmentCmd.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/AttachmentCmd.java new file mode 100644 index 000000000..f0112529e --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/AttachmentCmd.java @@ -0,0 +1,68 @@ +package org.dromara.workflow.flowable.cmd; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.domain.vo.SysOssVo; +import org.dromara.system.service.ISysOssService; +import org.flowable.common.engine.impl.interceptor.Command; +import org.flowable.common.engine.impl.interceptor.CommandContext; +import org.flowable.engine.impl.persistence.entity.AttachmentEntity; +import org.flowable.engine.impl.persistence.entity.AttachmentEntityManager; +import org.flowable.engine.impl.util.CommandContextUtil; + +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +/** + * 附件上传 + * + * @author may + */ +public class AttachmentCmd implements Command { + + private final String fileId; + + private final String taskId; + + private final String processInstanceId; + + public AttachmentCmd(String fileId, String taskId, String processInstanceId) { + this.fileId = fileId; + this.taskId = taskId; + this.processInstanceId = processInstanceId; + } + + @Override + public Boolean execute(CommandContext commandContext) { + try { + if (StringUtils.isNotBlank(fileId)) { + List fileIds = StreamUtils.toList(Arrays.asList(fileId.split(StrUtil.COMMA)), Long::valueOf); + List sysOssVos = SpringUtils.getBean(ISysOssService.class).listByIds(fileIds); + if (CollUtil.isNotEmpty(sysOssVos)) { + for (SysOssVo sysOssVo : sysOssVos) { + AttachmentEntityManager attachmentEntityManager = CommandContextUtil.getAttachmentEntityManager(); + AttachmentEntity attachmentEntity = attachmentEntityManager.create(); + attachmentEntity.setRevision(1); + attachmentEntity.setUserId(LoginHelper.getUserId().toString()); + attachmentEntity.setName(sysOssVo.getOriginalName()); + attachmentEntity.setDescription(sysOssVo.getOriginalName()); + attachmentEntity.setType(sysOssVo.getFileSuffix()); + attachmentEntity.setTaskId(taskId); + attachmentEntity.setProcessInstanceId(processInstanceId); + attachmentEntity.setContentId(sysOssVo.getOssId().toString()); + attachmentEntity.setTime(new Date()); + attachmentEntityManager.insert(attachmentEntity); + } + } + } + } catch (Exception e) { + throw new RuntimeException(e); + } + return true; + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/DeleteExecutionCmd.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/DeleteExecutionCmd.java new file mode 100644 index 000000000..215d31023 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/DeleteExecutionCmd.java @@ -0,0 +1,36 @@ +package org.dromara.workflow.flowable.cmd; + +import org.flowable.common.engine.impl.interceptor.Command; +import org.flowable.common.engine.impl.interceptor.CommandContext; +import org.flowable.engine.impl.persistence.entity.ExecutionEntity; +import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager; +import org.flowable.engine.impl.util.CommandContextUtil; + +import java.io.Serializable; + +/** + * 删除执行数据 + * + * @author may + */ +public class DeleteExecutionCmd implements Command, Serializable { + + /** + * 执行id + */ + private final String executionId; + + public DeleteExecutionCmd(String executionId) { + this.executionId = executionId; + } + + @Override + public Void execute(CommandContext commandContext) { + ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager(); + ExecutionEntity entity = executionEntityManager.findById(executionId); + if (entity != null) { + executionEntityManager.deleteExecutionAndRelatedData(entity, "", false, false); + } + return null; + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/DeleteSequenceMultiInstanceCmd.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/DeleteSequenceMultiInstanceCmd.java new file mode 100644 index 000000000..6773eefff --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/DeleteSequenceMultiInstanceCmd.java @@ -0,0 +1,82 @@ +package org.dromara.workflow.flowable.cmd; + +import cn.hutool.core.util.ObjectUtil; +import lombok.AllArgsConstructor; +import org.flowable.common.engine.impl.interceptor.Command; +import org.flowable.common.engine.impl.interceptor.CommandContext; +import org.flowable.engine.impl.persistence.entity.ExecutionEntity; +import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager; +import org.flowable.engine.impl.util.CommandContextUtil; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.dromara.workflow.common.constant.FlowConstant.LOOP_COUNTER; +import static org.dromara.workflow.common.constant.FlowConstant.NUMBER_OF_INSTANCES; + + +/** + * 串行减签 + * + * @author may + */ +@AllArgsConstructor +public class DeleteSequenceMultiInstanceCmd implements Command { + + /** + * 当前节点审批人员id + */ + private final String currentUserId; + + /** + * 执行id + */ + private final String executionId; + + /** + * 会签人员集合KEY + */ + private final String assigneeList; + + /** + * 减签人员 + */ + private final List assignees; + + + @Override + @SuppressWarnings("unchecked") + public Void execute(CommandContext commandContext) { + ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager(); + ExecutionEntity entity = executionEntityManager.findById(executionId); + // 设置流程变量 + List userIds = new ArrayList<>(); + List variable = (List) entity.getVariable(assigneeList); + for (Object o : variable) { + userIds.add(Long.valueOf(o.toString())); + } + List userIdList = new ArrayList<>(); + userIds.forEach(e -> { + Long userId = assignees.stream().filter(id -> ObjectUtil.equals(id, e)).findFirst().orElse(null); + if (userId == null) { + userIdList.add(e); + } + }); + // 当前任务执行位置 + int loopCounterIndex = -1; + for (int i = 0; i < userIdList.size(); i++) { + Long userId = userIdList.get(i); + if (currentUserId.equals(userId.toString())) { + loopCounterIndex = i; + } + } + Map variables = new HashMap<>(16); + variables.put(NUMBER_OF_INSTANCES, userIdList.size()); + variables.put(assigneeList, userIdList); + variables.put(LOOP_COUNTER, loopCounterIndex); + entity.setVariables(variables); + return null; + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/ExecutionChildByExecutionIdCmd.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/ExecutionChildByExecutionIdCmd.java new file mode 100644 index 000000000..1f3088bfc --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/ExecutionChildByExecutionIdCmd.java @@ -0,0 +1,39 @@ +package org.dromara.workflow.flowable.cmd; + +import org.dromara.common.core.utils.StreamUtils; +import org.flowable.common.engine.impl.interceptor.Command; +import org.flowable.common.engine.impl.interceptor.CommandContext; +import org.flowable.engine.impl.persistence.entity.ExecutionEntity; +import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager; +import org.flowable.engine.impl.util.CommandContextUtil; + +import java.io.Serializable; +import java.util.List; + +/** + * 获取并行网关执行后保留的执行实例数据 + * + * @author may + */ +public class ExecutionChildByExecutionIdCmd implements Command>, Serializable { + + /** + * 当前任务执行实例id + */ + private final String executionId; + + public ExecutionChildByExecutionIdCmd(String executionId) { + this.executionId = executionId; + } + + @Override + public List execute(CommandContext commandContext) { + ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager(); + // 获取当前执行数据 + ExecutionEntity executionEntity = executionEntityManager.findById(executionId); + // 通过当前执行数据的父执行,查询所有子执行数据 + List allChildrenExecution = + executionEntityManager.collectChildren(executionEntity.getParent()); + return StreamUtils.filter(allChildrenExecution, e -> !e.isActive()); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/UpdateBusinessStatusCmd.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/UpdateBusinessStatusCmd.java new file mode 100644 index 000000000..3ba120aef --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/UpdateBusinessStatusCmd.java @@ -0,0 +1,37 @@ +package org.dromara.workflow.flowable.cmd; + +import org.dromara.common.core.exception.ServiceException; +import org.flowable.common.engine.impl.interceptor.Command; +import org.flowable.common.engine.impl.interceptor.CommandContext; +import org.flowable.engine.impl.persistence.entity.HistoricProcessInstanceEntity; +import org.flowable.engine.impl.persistence.entity.HistoricProcessInstanceEntityManager; +import org.flowable.engine.impl.util.CommandContextUtil; + +/** + * 修改流程状态 + * + * @author may + */ +public class UpdateBusinessStatusCmd implements Command { + + private final String processInstanceId; + private final String status; + + public UpdateBusinessStatusCmd(String processInstanceId, String status) { + this.processInstanceId = processInstanceId; + this.status = status; + } + + @Override + public Boolean execute(CommandContext commandContext) { + try { + HistoricProcessInstanceEntityManager manager = CommandContextUtil.getHistoricProcessInstanceEntityManager(); + HistoricProcessInstanceEntity processInstance = manager.findById(processInstanceId); + processInstance.setBusinessStatus(status); + manager.update(processInstance); + return true; + } catch (Exception e) { + throw new ServiceException(e.getMessage()); + } + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/UpdateHiTaskInstCmd.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/UpdateHiTaskInstCmd.java new file mode 100644 index 000000000..42f6d1c78 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/UpdateHiTaskInstCmd.java @@ -0,0 +1,51 @@ +package org.dromara.workflow.flowable.cmd; + +import org.dromara.common.core.exception.ServiceException; +import org.flowable.common.engine.impl.interceptor.Command; +import org.flowable.common.engine.impl.interceptor.CommandContext; +import org.flowable.engine.impl.util.CommandContextUtil; +import org.flowable.task.service.HistoricTaskService; +import org.flowable.task.service.impl.persistence.entity.HistoricTaskInstanceEntity; + +import java.util.Date; +import java.util.List; + + +/** + * 修改流程历史 + * + * @author may + */ +public class UpdateHiTaskInstCmd implements Command { + + private final List taskIds; + + private final String processDefinitionId; + + private final String processInstanceId; + + public UpdateHiTaskInstCmd(List taskIds, String processDefinitionId, String processInstanceId) { + this.taskIds = taskIds; + this.processDefinitionId = processDefinitionId; + this.processInstanceId = processInstanceId; + } + + @Override + public Boolean execute(CommandContext commandContext) { + try { + HistoricTaskService historicTaskService = CommandContextUtil.getHistoricTaskService(); + for (String taskId : taskIds) { + HistoricTaskInstanceEntity historicTask = historicTaskService.getHistoricTask(taskId); + if (historicTask != null) { + historicTask.setProcessDefinitionId(processDefinitionId); + historicTask.setProcessInstanceId(processInstanceId); + historicTask.setCreateTime(new Date()); + CommandContextUtil.getHistoricTaskService().updateHistoricTask(historicTask, true); + } + } + return true; + } catch (Exception e) { + throw new ServiceException(e.getMessage()); + } + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/config/FlowableConfig.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/config/FlowableConfig.java new file mode 100644 index 000000000..1494bf37f --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/config/FlowableConfig.java @@ -0,0 +1,32 @@ +package org.dromara.workflow.flowable.config; + +import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; +import org.dromara.workflow.flowable.handler.TaskTimeoutJobHandler; +import org.flowable.spring.SpringProcessEngineConfiguration; +import org.flowable.spring.boot.EngineConfigurationConfigurer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; + +import java.util.Collections; + + +/** + * flowable配置 + * + * @author may + */ +@Configuration +public class FlowableConfig implements EngineConfigurationConfigurer { + + @Autowired + private GlobalFlowableListener globalFlowableListener; + @Autowired + private IdentifierGenerator identifierGenerator; + + @Override + public void configure(SpringProcessEngineConfiguration processEngineConfiguration) { + processEngineConfiguration.setIdGenerator(() -> identifierGenerator.nextId(null).toString()); + processEngineConfiguration.setEventListeners(Collections.singletonList(globalFlowableListener)); + processEngineConfiguration.addCustomJobHandler(new TaskTimeoutJobHandler()); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/config/GlobalFlowableListener.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/config/GlobalFlowableListener.java new file mode 100644 index 000000000..9bb971a8c --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/config/GlobalFlowableListener.java @@ -0,0 +1,139 @@ +package org.dromara.workflow.flowable.config; + +import cn.hutool.core.collection.CollUtil; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.workflow.common.enums.TaskStatusEnum; +import org.dromara.workflow.flowable.handler.TaskTimeoutJobHandler; +import org.dromara.workflow.utils.QueryUtils; +import org.flowable.bpmn.model.BoundaryEvent; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.FlowElement; +import org.flowable.common.engine.api.delegate.event.*; +import org.flowable.common.engine.impl.cfg.TransactionState; +import org.flowable.engine.RepositoryService; +import org.flowable.engine.RuntimeService; +import org.flowable.engine.TaskService; +import org.flowable.engine.impl.util.CommandContextUtil; +import org.flowable.engine.runtime.Execution; +import org.flowable.engine.task.Comment; +import org.flowable.job.service.TimerJobService; +import org.flowable.job.service.impl.persistence.entity.JobEntity; +import org.flowable.job.service.impl.persistence.entity.TimerJobEntity; +import org.flowable.task.api.Task; +import org.flowable.task.service.impl.persistence.entity.TaskEntity; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +import java.util.Date; +import java.util.List; + + +/** + * 引擎调度监听 + * + * @author may + */ +@Component +public class GlobalFlowableListener implements FlowableEventListener { + + @Autowired + @Lazy + private TaskService taskService; + + @Autowired + @Lazy + private RuntimeService runtimeService; + + @Autowired + @Lazy + private RepositoryService repositoryService; + + @Value("${flowable.async-executor-activate}") + private boolean asyncExecutorActivate; + + @Override + public void onEvent(FlowableEvent flowableEvent) { + if (flowableEvent instanceof FlowableEngineEvent flowableEngineEvent) { + FlowableEngineEventType engineEventType = (FlowableEngineEventType) flowableEvent.getType(); + switch (engineEventType) { + case JOB_EXECUTION_SUCCESS -> jobExecutionSuccess((FlowableEngineEntityEvent) flowableEngineEvent); + case TASK_DUEDATE_CHANGED, TASK_CREATED -> { + FlowableEntityEvent flowableEntityEvent = (FlowableEntityEvent) flowableEngineEvent; + Object entityObject = flowableEntityEvent.getEntity(); + TaskEntity task = (TaskEntity) entityObject; + if (asyncExecutorActivate && task.getDueDate() != null && task.getDueDate().after(new Date())) { + //删除之前已经存在的定时任务 + TimerJobService timerJobService = CommandContextUtil.getTimerJobService(); + List timerJobEntityList = timerJobService.findTimerJobsByProcessInstanceId(task.getProcessInstanceId()); + if (!CollUtil.isEmpty(timerJobEntityList)) { + for (TimerJobEntity timerJobEntity : timerJobEntityList) { + String taskId = timerJobEntity.getJobHandlerConfiguration(); + if (task.getId().equals(taskId)) { + timerJobService.deleteTimerJob(timerJobEntity); + } + } + } + //创建job对象 + TimerJobEntity timer = timerJobService.createTimerJob(); + timer.setTenantId(TenantHelper.getTenantId()); + //设置job类型 + timer.setJobType(JobEntity.JOB_TYPE_TIMER); + timer.setJobHandlerType(TaskTimeoutJobHandler.TYPE); + timer.setDuedate(task.getDueDate()); + timer.setProcessInstanceId(task.getProcessInstanceId()); + //设置任务id + timer.setJobHandlerConfiguration(task.getId()); + //保存并触发事件 + timerJobService.scheduleTimerJob(timer); + } + } + } + } + } + + @Override + public boolean isFailOnException() { + return true; + } + + @Override + public boolean isFireOnTransactionLifecycleEvent() { + return false; + } + + @Override + public String getOnTransaction() { + return TransactionState.COMMITTED.name(); + } + + /** + * 处理边界定时事件自动审批记录 + * + * @param event 事件 + */ + protected void jobExecutionSuccess(FlowableEngineEntityEvent event) { + if (event != null && StringUtils.isNotBlank(event.getExecutionId())) { + Execution execution = runtimeService.createExecutionQuery().executionId(event.getExecutionId()).singleResult(); + if (execution != null) { + BpmnModel bpmnModel = repositoryService.getBpmnModel(event.getProcessDefinitionId()); + FlowElement flowElement = bpmnModel.getFlowElement(execution.getActivityId()); + if (flowElement instanceof BoundaryEvent) { + String attachedToRefId = ((BoundaryEvent) flowElement).getAttachedToRefId(); + List list = runtimeService.createExecutionQuery().activityId(attachedToRefId).list(); + for (Execution ex : list) { + Task task = QueryUtils.taskQuery().executionId(ex.getId()).singleResult(); + if (task != null) { + List taskComments = taskService.getTaskComments(task.getId()); + if (CollUtil.isEmpty(taskComments)) { + taskService.addComment(task.getId(), task.getProcessInstanceId(), TaskStatusEnum.PASS.getStatus(), "超时自动审批!"); + } + } + } + } + } + } + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/handler/TaskTimeoutJobHandler.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/handler/TaskTimeoutJobHandler.java new file mode 100644 index 000000000..7685423fc --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/handler/TaskTimeoutJobHandler.java @@ -0,0 +1,38 @@ +package org.dromara.workflow.flowable.handler; + +import org.dromara.workflow.common.enums.TaskStatusEnum; +import org.flowable.common.engine.impl.interceptor.CommandContext; +import org.flowable.engine.TaskService; +import org.flowable.engine.impl.jobexecutor.TimerEventHandler; +import org.flowable.engine.impl.util.CommandContextUtil; +import org.flowable.job.service.JobHandler; +import org.flowable.job.service.impl.persistence.entity.JobEntity; +import org.flowable.task.api.Task; +import org.flowable.task.api.TaskQuery; +import org.flowable.variable.api.delegate.VariableScope; + +/** + * 办理超时(过期)任务 + * + * @author may + */ +public class TaskTimeoutJobHandler extends TimerEventHandler implements JobHandler { + + public static final String TYPE = "taskTimeout"; + + @Override + public String getType() { + return TYPE; + } + + @Override + public void execute(JobEntity job, String configuration, VariableScope variableScope, CommandContext commandContext) { + TaskService taskService = CommandContextUtil.getProcessEngineConfiguration(commandContext) + .getTaskService(); + Task task = taskService.createTaskQuery().taskId(configuration).singleResult(); + if (task != null) { + taskService.addComment(task.getId(), task.getProcessInstanceId(), TaskStatusEnum.TIMEOUT.getStatus(), "超时自动审批!"); + taskService.complete(configuration); + } + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/strategy/FlowEventStrategy.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/strategy/FlowEventStrategy.java new file mode 100644 index 000000000..9da577633 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/strategy/FlowEventStrategy.java @@ -0,0 +1,73 @@ +package org.dromara.workflow.flowable.strategy; + +import org.dromara.common.core.utils.StringUtils; +import org.dromara.workflow.annotation.FlowListenerAnnotation; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +/** + * 流程任务监听策略 + * + * @author may + * @date 2023-12-27 + */ +@Component +public class FlowEventStrategy implements BeanPostProcessor { + + private final Map flowTaskEventHandlers = new HashMap<>(); + private final Map flowProcessEventHandlers = new HashMap<>(); + + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { + if (bean instanceof FlowTaskEventHandler) { + FlowListenerAnnotation annotation = bean.getClass().getAnnotation(FlowListenerAnnotation.class); + if (null != annotation) { + if (StringUtils.isNotBlank(annotation.processDefinitionKey()) && StringUtils.isNotBlank(annotation.taskDefId())) { + String id = annotation.processDefinitionKey() + "_" + annotation.taskDefId(); + if (!flowTaskEventHandlers.containsKey(id)) { + flowTaskEventHandlers.put(id, (FlowTaskEventHandler) bean); + } + } + } + } + if (bean instanceof FlowProcessEventHandler) { + FlowListenerAnnotation annotation = bean.getClass().getAnnotation(FlowListenerAnnotation.class); + if (null != annotation) { + if (StringUtils.isNotBlank(annotation.processDefinitionKey()) && StringUtils.isBlank(annotation.taskDefId())) { + if (!flowProcessEventHandlers.containsKey(annotation.processDefinitionKey())) { + flowProcessEventHandlers.put(annotation.processDefinitionKey(), (FlowProcessEventHandler) bean); + } + } + } + } + return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName); + } + + /** + * 获取可执行bean + * + * @param key key + */ + public FlowTaskEventHandler getTaskHandler(String key) { + if (!flowTaskEventHandlers.containsKey(key)) { + return null; + } + return flowTaskEventHandlers.get(key); + } + + /** + * 获取可执行bean + * + * @param key key + */ + public FlowProcessEventHandler getProcessHandler(String key) { + if (!flowProcessEventHandlers.containsKey(key)) { + return null; + } + return flowProcessEventHandlers.get(key); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/strategy/FlowProcessEventHandler.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/strategy/FlowProcessEventHandler.java new file mode 100644 index 000000000..4af2c4784 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/strategy/FlowProcessEventHandler.java @@ -0,0 +1,20 @@ +package org.dromara.workflow.flowable.strategy; + + +/** + * 流程监听 + * + * @author may + * @date 2023-12-27 + */ +public interface FlowProcessEventHandler { + + /** + * 执行办理任务监听 + * + * @param businessKey 业务id + * @param status 状态 + * @param submit 当为true时为申请人节点办理 + */ + void handleProcess(String businessKey, String status, boolean submit); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/strategy/FlowTaskEventHandler.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/strategy/FlowTaskEventHandler.java new file mode 100644 index 000000000..b338900e2 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/strategy/FlowTaskEventHandler.java @@ -0,0 +1,19 @@ +package org.dromara.workflow.flowable.strategy; + + +/** + * 流程任务监听 + * + * @author may + * @date 2023-12-27 + */ +public interface FlowTaskEventHandler { + + /** + * 执行办理任务监听 + * + * @param taskId 任务ID + * @param businessKey 业务id + */ + void handleTask(String taskId, String businessKey); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/TestCustomProcessHandler.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/TestCustomProcessHandler.java new file mode 100644 index 000000000..29886d8d4 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/TestCustomProcessHandler.java @@ -0,0 +1,31 @@ +package org.dromara.workflow.listener; + +import lombok.extern.slf4j.Slf4j; +import org.dromara.workflow.annotation.FlowListenerAnnotation; +import org.dromara.workflow.flowable.strategy.FlowProcessEventHandler; +import org.springframework.stereotype.Component; + +/** + * 自定义监听测试 + * + * @author may + * @date 2023-12-27 + */ +@Slf4j +@Component +@FlowListenerAnnotation(processDefinitionKey = "leave1") +public class TestCustomProcessHandler implements FlowProcessEventHandler { + + + /** + * 执行办理任务监听 + * + * @param businessKey 业务id + * @param status 状态 + * @param submit 当为true时为申请人节点办理 + */ + @Override + public void handleProcess(String businessKey, String status, boolean submit) { + log.info("业务ID:" + businessKey + ",状态:" + status); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/TestCustomTaskHandler.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/TestCustomTaskHandler.java new file mode 100644 index 000000000..d85286df7 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/TestCustomTaskHandler.java @@ -0,0 +1,23 @@ +package org.dromara.workflow.listener; + +import lombok.extern.slf4j.Slf4j; +import org.dromara.workflow.annotation.FlowListenerAnnotation; +import org.dromara.workflow.flowable.strategy.FlowTaskEventHandler; +import org.springframework.stereotype.Component; + +/** + * 自定义监听测试 + * + * @author may + * @date 2023-12-27 + */ +@Slf4j +@Component +@FlowListenerAnnotation(processDefinitionKey = "leave1", taskDefId = "Activity_14633hx") +public class TestCustomTaskHandler implements FlowTaskEventHandler { + + @Override + public void handleTask(String taskId, String businessKey) { + log.info("任务ID:" + taskId + ",业务ID:" + businessKey); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/TestLeaveExecutionListener.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/TestLeaveExecutionListener.java new file mode 100644 index 000000000..11f844e4a --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/TestLeaveExecutionListener.java @@ -0,0 +1,28 @@ +package org.dromara.workflow.listener; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.workflow.utils.QueryUtils; +import org.flowable.engine.TaskService; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.delegate.ExecutionListener; +import org.flowable.task.api.Task; +import org.springframework.stereotype.Component; + +/** + * 流程实例监听测试 + * + * @author may + * @date 2023-12-12 + */ +@Slf4j +@RequiredArgsConstructor +@Component("testLeaveExecutionListener") +public class TestLeaveExecutionListener implements ExecutionListener { + + @Override + public void notify(DelegateExecution execution) { + Task task = QueryUtils.taskQuery().executionId(execution.getId()).singleResult(); + log.info("执行监听【" + task.getName() + "】"); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/TestLeaveTaskListener.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/TestLeaveTaskListener.java new file mode 100644 index 000000000..5c62417a2 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/TestLeaveTaskListener.java @@ -0,0 +1,21 @@ +package org.dromara.workflow.listener; + +import lombok.extern.slf4j.Slf4j; +import org.flowable.task.service.delegate.DelegateTask; +import org.flowable.task.service.delegate.TaskListener; +import org.springframework.stereotype.Component; + +/** + * 流程任务监听测试 + * + * @author may + * @date 2023-12-12 + */ +@Slf4j +@Component("testLeaveTaskListener") +public class TestLeaveTaskListener implements TaskListener { + @Override + public void notify(DelegateTask delegateTask) { + log.info("执行监听【" + delegateTask.getName() + "】"); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/ActHiProcinstMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/ActHiProcinstMapper.java new file mode 100644 index 000000000..a3a41c924 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/ActHiProcinstMapper.java @@ -0,0 +1,16 @@ +package org.dromara.workflow.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.workflow.domain.ActHiProcinst; + +/** + * 流程实例Mapper接口 + * + * @author may + * @date 2023-07-22 + */ +@InterceptorIgnore(tenantLine = "true") +public interface ActHiProcinstMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/ActHiTaskinstMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/ActHiTaskinstMapper.java new file mode 100644 index 000000000..63b394b6f --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/ActHiTaskinstMapper.java @@ -0,0 +1,16 @@ +package org.dromara.workflow.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import org.dromara.workflow.domain.ActHiTaskinst; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 流程历史任务Mapper接口 + * + * @author may + * @date 2024-03-02 + */ +@InterceptorIgnore(tenantLine = "true") +public interface ActHiTaskinstMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/ActTaskMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/ActTaskMapper.java new file mode 100644 index 000000000..63c5ecb7b --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/ActTaskMapper.java @@ -0,0 +1,47 @@ +package org.dromara.workflow.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Param; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.workflow.domain.vo.TaskVo; + + +/** + * 任务信息Mapper接口 + * + * @author may + * @date 2024-03-02 + */ +@InterceptorIgnore(tenantLine = "true") +public interface ActTaskMapper extends BaseMapperPlus { + /** + * 获取待办信息 + * + * @param page 分页 + * @param queryWrapper 条件 + * @return 结果 + */ + Page getTaskWaitByPage(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 获取已办 + * + * @param page 分页 + * @param queryWrapper 条件 + * @return 结果 + */ + Page getTaskFinishByPage(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 查询当前用户的抄送 + * + * @param page 分页 + * @param queryWrapper 条件 + * @return 结果 + */ + Page getTaskCopyByPage(@Param("page") Page page, @Param(Constants.WRAPPER) QueryWrapper queryWrapper); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/TestLeaveMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/TestLeaveMapper.java new file mode 100644 index 000000000..cd1edba89 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/TestLeaveMapper.java @@ -0,0 +1,15 @@ +package org.dromara.workflow.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.workflow.domain.TestLeave; +import org.dromara.workflow.domain.vo.TestLeaveVo; + +/** + * 请假Mapper接口 + * + * @author may + * @date 2023-07-21 + */ +public interface TestLeaveMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfCategoryMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfCategoryMapper.java new file mode 100644 index 000000000..98aea024e --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfCategoryMapper.java @@ -0,0 +1,15 @@ +package org.dromara.workflow.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.workflow.domain.WfCategory; +import org.dromara.workflow.domain.vo.WfCategoryVo; + +/** + * 流程分类Mapper接口 + * + * @author may + * @date 2023-06-27 + */ +public interface WfCategoryMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfDefinitionConfigMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfDefinitionConfigMapper.java new file mode 100644 index 000000000..ee2088255 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfDefinitionConfigMapper.java @@ -0,0 +1,15 @@ +package org.dromara.workflow.mapper; + +import org.dromara.workflow.domain.WfDefinitionConfig; +import org.dromara.workflow.domain.vo.WfDefinitionConfigVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 流程定义配置Mapper接口 + * + * @author may + * @date 2024-03-18 + */ +public interface WfDefinitionConfigMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfFormManageMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfFormManageMapper.java new file mode 100644 index 000000000..acf8111ad --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfFormManageMapper.java @@ -0,0 +1,15 @@ +package org.dromara.workflow.mapper; + +import org.dromara.workflow.domain.WfFormManage; +import org.dromara.workflow.domain.vo.WfFormManageVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 表单管理Mapper接口 + * + * @author may + * @date 2024-03-29 + */ +public interface WfFormManageMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfNodeConfigMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfNodeConfigMapper.java new file mode 100644 index 000000000..d2aecacb9 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfNodeConfigMapper.java @@ -0,0 +1,15 @@ +package org.dromara.workflow.mapper; + +import org.dromara.workflow.domain.WfNodeConfig; +import org.dromara.workflow.domain.vo.WfNodeConfigVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 节点配置Mapper接口 + * + * @author may + * @date 2024-03-30 + */ +public interface WfNodeConfigMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfTaskBackNodeMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfTaskBackNodeMapper.java new file mode 100644 index 000000000..9b291feb4 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfTaskBackNodeMapper.java @@ -0,0 +1,13 @@ +package org.dromara.workflow.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.workflow.domain.WfTaskBackNode; + +/** + * 节点驳回记录Mapper接口 + * + * @author may + * @date 2024-03-13 + */ +public interface WfTaskBackNodeMapper extends BaseMapperPlus { +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActHiProcinstService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActHiProcinstService.java new file mode 100644 index 000000000..e802c6972 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActHiProcinstService.java @@ -0,0 +1,31 @@ +package org.dromara.workflow.service; + + +import org.dromara.workflow.domain.ActHiProcinst; + +import java.util.List; + +/** + * 流程实例Service接口 + * + * @author may + * @date 2023-07-22 + */ +public interface IActHiProcinstService { + + /** + * 按照业务id查询 + * + * @param businessKeys 业务id + * @return 结果 + */ + List selectByBusinessKeyIn(List businessKeys); + + /** + * 按照业务id查询 + * + * @param businessKey 业务id + * @return 结果 + */ + ActHiProcinst selectByBusinessKey(String businessKey); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActHiTaskinstService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActHiTaskinstService.java new file mode 100644 index 000000000..ad286e242 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActHiTaskinstService.java @@ -0,0 +1,11 @@ +package org.dromara.workflow.service; + + +/** + * 流程历史任务Service接口 + * + * @author may + * @date 2024-03-02 + */ +public interface IActHiTaskinstService { +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActModelService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActModelService.java new file mode 100644 index 000000000..4a6d17062 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActModelService.java @@ -0,0 +1,83 @@ +package org.dromara.workflow.service; + +import jakarta.servlet.http.HttpServletResponse; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.workflow.domain.bo.ModelBo; +import org.dromara.workflow.domain.vo.ModelVo; +import org.flowable.engine.repository.Model; + +import java.util.List; + + +/** + * 模型管理 服务层 + * + * @author may + */ +public interface IActModelService { + /** + * 分页查询模型 + * + * @param modelBo 模型参数 + * @param pageQuery 参数 + * @return 返回分页列表 + */ + TableDataInfo page(ModelBo modelBo, PageQuery pageQuery); + + /** + * 新增模型 + * + * @param modelBo 模型请求对象 + * @return 结果 + */ + boolean saveNewModel(ModelBo modelBo); + + /** + * 查询模型 + * + * @param modelId 模型id + * @return 模型数据 + */ + ModelVo getInfo(String modelId); + + /** + * 修改模型信息 + * + * @param modelBo 模型数据 + * @return 结果 + */ + boolean update(ModelBo modelBo); + + /** + * 编辑模型XML + * + * @param modelBo 模型数据 + * @return 结果 + */ + boolean editModelXml(ModelBo modelBo); + + /** + * 模型部署 + * + * @param id 模型id + * @return 结果 + */ + boolean modelDeploy(String id); + + /** + * 导出模型zip压缩包 + * + * @param modelIds 模型id + * @param response 响应 + */ + void exportZip(List modelIds, HttpServletResponse response); + + /** + * 复制模型 + * + * @param modelBo 模型数据 + * @return 结果 + */ + boolean copyModel(ModelBo modelBo); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActProcessDefinitionService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActProcessDefinitionService.java new file mode 100644 index 000000000..5d00e4199 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActProcessDefinitionService.java @@ -0,0 +1,91 @@ +package org.dromara.workflow.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.workflow.domain.bo.ProcessDefinitionBo; +import org.dromara.workflow.domain.vo.ProcessDefinitionVo; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +/** + * 流程定义 服务层 + * + * @author may + */ +public interface IActProcessDefinitionService { + /** + * 分页查询 + * + * @param processDefinitionBo 参数 + * @param pageQuery 分页 + * @return 返回分页列表 + */ + TableDataInfo page(ProcessDefinitionBo processDefinitionBo, PageQuery pageQuery); + + /** + * 查询历史流程定义列表 + * + * @param key 流程定义key + * @return 结果 + */ + List getListByKey(String key); + + /** + * 查看流程定义图片 + * + * @param processDefinitionId 流程定义id + * @return 结果 + */ + String definitionImage(String processDefinitionId); + + /** + * 查看流程定义xml文件 + * + * @param processDefinitionId 流程定义id + * @return 结果 + */ + String definitionXml(String processDefinitionId); + + /** + * 删除流程定义 + * + * @param deploymentIds 部署id + * @param processDefinitionIds 流程定义id + * @return 结果 + */ + boolean deleteDeployment(List deploymentIds, List processDefinitionIds); + + /** + * 激活或者挂起流程定义 + * + * @param processDefinitionId 流程定义id + * @return 结果 + */ + boolean updateDefinitionState(String processDefinitionId); + + /** + * 迁移流程定义 + * + * @param currentProcessDefinitionId 当前流程定义id + * @param fromProcessDefinitionId 需要迁移到的流程定义id + * @return 结果 + */ + boolean migrationDefinition(String currentProcessDefinitionId, String fromProcessDefinitionId); + + /** + * 流程定义转换为模型 + * + * @param processDefinitionId 流程定义id + * @return 结果 + */ + boolean convertToModel(String processDefinitionId); + + /** + * 通过zip或xml部署流程定义 + * + * @param file 文件 + * @param categoryCode 分类 + */ + void deployByFile(MultipartFile file, String categoryCode); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActProcessInstanceService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActProcessInstanceService.java new file mode 100644 index 000000000..388680455 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActProcessInstanceService.java @@ -0,0 +1,117 @@ +package org.dromara.workflow.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.workflow.domain.bo.ProcessInstanceBo; +import org.dromara.workflow.domain.bo.ProcessInvalidBo; +import org.dromara.workflow.domain.bo.TaskUrgingBo; +import org.dromara.workflow.domain.vo.ProcessInstanceVo; + +import java.util.List; +import java.util.Map; + +/** + * 流程实例 服务层 + * + * @author may + */ +public interface IActProcessInstanceService { + /** + * 通过流程实例id获取历史流程图 + * + * @param processInstanceId 流程实例id + * @return 结果 + */ + String getHistoryImage(String processInstanceId); + + /** + * 通过流程实例id获取历史流程图运行中,历史等节点 + * + * @param processInstanceId 流程实例id + * @return 结果 + */ + Map getHistoryList(String processInstanceId); + + /** + * 分页查询正在运行的流程实例 + * + * @param processInstanceBo 参数 + * @param pageQuery 分页 + * @return 结果 + */ + TableDataInfo getPageByRunning(ProcessInstanceBo processInstanceBo, PageQuery pageQuery); + + /** + * 分页查询已结束的流程实例 + * + * @param processInstanceBo 参数 + * @param pageQuery 分页 + * @return 结果 + */ + TableDataInfo getPageByFinish(ProcessInstanceBo processInstanceBo, PageQuery pageQuery); + + /** + * 获取审批记录 + * + * @param processInstanceId 流程实例id + * @return 结果 + */ + Map getHistoryRecord(String processInstanceId); + + /** + * 作废流程实例,不会删除历史记录(删除运行中的实例) + * + * @param processInvalidBo 参数 + * @return 结果 + */ + boolean deleteRunInstance(ProcessInvalidBo processInvalidBo); + + /** + * 运行中的实例 删除程实例,删除历史记录,删除业务与流程关联信息 + * + * @param processInstanceIds 流程实例id + * @return 结果 + */ + boolean deleteRunAndHisInstance(List processInstanceIds); + + /** + * 按照业务id删除 运行中的实例 删除程实例,删除历史记录,删除业务与流程关联信息 + * + * @param businessKeys 业务id + * @return 结果 + */ + boolean deleteRunAndHisInstanceByBusinessKeys(List businessKeys); + + /** + * 已完成的实例 删除程实例,删除历史记录,删除业务与流程关联信息 + * + * @param processInstanceIds 流程实例id + * @return 结果 + */ + boolean deleteFinishAndHisInstance(List processInstanceIds); + + /** + * 撤销流程申请 + * + * @param processInstanceId 流程实例id + * @return 结果 + */ + boolean cancelProcessApply(String processInstanceId); + + /** + * 分页查询当前登录人单据 + * + * @param processInstanceBo 参数 + * @param pageQuery 分页 + * @return 结果 + */ + TableDataInfo getPageByCurrent(ProcessInstanceBo processInstanceBo, PageQuery pageQuery); + + /** + * 任务催办(给当前任务办理人发送站内信,邮件,短信等) + * + * @param taskUrgingBo 任务催办 + * @return 结果 + */ + boolean taskUrging(TaskUrgingBo taskUrgingBo); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActTaskService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActTaskService.java new file mode 100644 index 000000000..45c3de230 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActTaskService.java @@ -0,0 +1,145 @@ +package org.dromara.workflow.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.workflow.domain.bo.*; +import org.dromara.workflow.domain.vo.TaskVo; +import org.dromara.workflow.domain.vo.VariableVo; + +import java.util.List; +import java.util.Map; + +/** + * 任务 服务层 + * + * @author may + */ +public interface IActTaskService { + /** + * 启动任务 + * + * @param startProcessBo 启动流程参数 + * @return 结果 + */ + Map startWorkFlow(StartProcessBo startProcessBo); + + + /** + * 办理任务 + * + * @param completeTaskBo 办理任务参数 + * @return 结果 + */ + boolean completeTask(CompleteTaskBo completeTaskBo); + + /** + * 查询当前用户的待办任务 + * + * @param taskBo 参数 + * @param pageQuery 分页 + * @return 结果 + */ + TableDataInfo getPageByTaskWait(TaskBo taskBo, PageQuery pageQuery); + + /** + * 查询当前租户所有待办任务 + * + * @param taskBo 参数 + * @param pageQuery 分页 + * @return 结果 + */ + TableDataInfo getPageByAllTaskWait(TaskBo taskBo, PageQuery pageQuery); + + + /** + * 查询当前用户的已办任务 + * + * @param taskBo 参数 + * @param pageQuery 参数 + * @return 结果 + */ + TableDataInfo getPageByTaskFinish(TaskBo taskBo, PageQuery pageQuery); + + /** + * 查询当前用户的抄送 + * + * @param taskBo 参数 + * @param pageQuery 参数 + * @return 结果 + */ + TableDataInfo getPageByTaskCopy(TaskBo taskBo, PageQuery pageQuery); + + /** + * 查询当前租户所有已办任务 + * + * @param taskBo 参数 + * @param pageQuery 参数 + * @return 结果 + */ + TableDataInfo getPageByAllTaskFinish(TaskBo taskBo, PageQuery pageQuery); + + /** + * 委派任务 + * + * @param delegateBo 参数 + * @return 结果 + */ + boolean delegateTask(DelegateBo delegateBo); + + /** + * 终止任务 + * + * @param terminationBo 参数 + * @return 结果 + */ + boolean terminationTask(TerminationBo terminationBo); + + /** + * 转办任务 + * + * @param transmitBo 参数 + * @return 结果 + */ + boolean transferTask(TransmitBo transmitBo); + + /** + * 会签任务加签 + * + * @param addMultiBo 参数 + * @return 结果 + */ + boolean addMultiInstanceExecution(AddMultiBo addMultiBo); + + /** + * 会签任务减签 + * + * @param deleteMultiBo 参数 + * @return 结果 + */ + boolean deleteMultiInstanceExecution(DeleteMultiBo deleteMultiBo); + + /** + * 驳回审批 + * + * @param backProcessBo 参数 + * @return 流程实例id + */ + String backProcess(BackProcessBo backProcessBo); + + /** + * 修改任务办理人 + * + * @param taskIds 任务id + * @param userId 办理人id + * @return 结果 + */ + boolean updateAssignee(String[] taskIds, String userId); + + /** + * 查询流程变量 + * + * @param taskId 任务id + * @return 结果 + */ + List getInstanceVariable(String taskId); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/ITestLeaveService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/ITestLeaveService.java new file mode 100644 index 000000000..5c95547a5 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/ITestLeaveService.java @@ -0,0 +1,49 @@ +package org.dromara.workflow.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.workflow.domain.TestLeave; +import org.dromara.workflow.domain.bo.TestLeaveBo; +import org.dromara.workflow.domain.vo.TestLeaveVo; + +import java.util.Collection; +import java.util.List; + +/** + * 请假Service接口 + * + * @author may + * @date 2023-07-21 + */ +public interface ITestLeaveService { + + /** + * 查询请假 + */ + TestLeaveVo queryById(Long id); + + /** + * 查询请假列表 + */ + TableDataInfo queryPageList(TestLeaveBo bo, PageQuery pageQuery); + + /** + * 查询请假列表 + */ + List queryList(TestLeaveBo bo); + + /** + * 新增请假 + */ + TestLeaveVo insertByBo(TestLeaveBo bo); + + /** + * 修改请假 + */ + TestLeaveVo updateByBo(TestLeaveBo bo); + + /** + * 校验并批量删除请假信息 + */ + Boolean deleteWithValidByIds(Collection ids); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfCategoryService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfCategoryService.java new file mode 100644 index 000000000..acf0aa2bc --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfCategoryService.java @@ -0,0 +1,51 @@ +package org.dromara.workflow.service; + +import org.dromara.workflow.domain.WfCategory; +import org.dromara.workflow.domain.bo.WfCategoryBo; +import org.dromara.workflow.domain.vo.WfCategoryVo; + +import java.util.Collection; +import java.util.List; + +/** + * 流程分类Service接口 + * + * @author may + * @date 2023-06-28 + */ +public interface IWfCategoryService { + + /** + * 查询流程分类 + */ + WfCategoryVo queryById(Long id); + + + /** + * 查询流程分类列表 + */ + List queryList(WfCategoryBo bo); + + /** + * 新增流程分类 + */ + Boolean insertByBo(WfCategoryBo bo); + + /** + * 修改流程分类 + */ + Boolean updateByBo(WfCategoryBo bo); + + /** + * 校验并批量删除流程分类信息 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 按照类别编码查询 + * + * @param categoryCode 分类比吗 + * @return 结果 + */ + WfCategory queryByCategoryCode(String categoryCode); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfDefinitionConfigService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfDefinitionConfigService.java new file mode 100644 index 000000000..fe5cf7ad3 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfDefinitionConfigService.java @@ -0,0 +1,83 @@ +package org.dromara.workflow.service; + +import org.dromara.workflow.domain.vo.WfDefinitionConfigVo; +import org.dromara.workflow.domain.bo.WfDefinitionConfigBo; + +import java.util.Collection; +import java.util.List; + +/** + * 流程定义配置Service接口 + * + * @author may + * @date 2024-03-18 + */ +public interface IWfDefinitionConfigService { + + /** + * 查询流程定义配置 + * + * @param definitionId 流程定义id + * @return 结果 + */ + WfDefinitionConfigVo getByDefId(String definitionId); + + /** + * 查询流程定义配置 + * + * @param tableName 表名 + * @return 结果 + */ + WfDefinitionConfigVo getByTableNameLastVersion(String tableName); + + /** + * 查询流程定义配置 + * + * @param definitionId 流程定义id + * @param tableName 表名 + * @return 结果 + */ + WfDefinitionConfigVo getByDefIdAndTableName(String definitionId, String tableName); + + /** + * 查询流程定义配置排除当前查询的流程定义 + * + * @param definitionId 流程定义id + * @param tableName 表名 + * @return 结果 + */ + List getByTableNameNotDefId(String tableName, String definitionId); + + /** + * 查询流程定义配置列表 + * + * @param definitionIds 流程定义id + * @return 结果 + */ + List queryList(List definitionIds); + + + /** + * 新增流程定义配置 + * + * @param bo 参数 + * @return 结果 + */ + Boolean saveOrUpdate(WfDefinitionConfigBo bo); + + /** + * 删除 + * + * @param ids id + * @return 结果 + */ + Boolean deleteByIds(Collection ids); + + /** + * 按照流程定义id删除 + * + * @param ids 流程定义id + * @return 结果 + */ + Boolean deleteByDefIds(Collection ids); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfFormManageService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfFormManageService.java new file mode 100644 index 000000000..2ca2264b0 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfFormManageService.java @@ -0,0 +1,81 @@ +package org.dromara.workflow.service; + +import org.dromara.workflow.domain.vo.WfFormManageVo; +import org.dromara.workflow.domain.bo.WfFormManageBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; + +import java.util.Collection; +import java.util.List; + +/** + * 表单管理Service接口 + * + * @author may + * @date 2024-03-29 + */ +public interface IWfFormManageService { + + /** + * 查询表单管理 + * + * @param id 主键 + * @return 结果 + */ + WfFormManageVo queryById(Long id); + + /** + * 查询表单管理 + * + * @param ids 主键 + * @return 结果 + */ + List queryByIds(List ids); + + /** + * 查询表单管理列表 + * + * @param bo 参数 + * @param pageQuery 分页 + * @return 结果 + */ + TableDataInfo queryPageList(WfFormManageBo bo, PageQuery pageQuery); + + /** + * 查询表单管理列表 + * + * @return 结果 + */ + List selectList(); + /** + * 查询表单管理列表 + * + * @param bo 参数 + * @return 结果 + */ + List queryList(WfFormManageBo bo); + + /** + * 新增表单管理 + * + * @param bo 参数 + * @return 结果 + */ + Boolean insertByBo(WfFormManageBo bo); + + /** + * 修改表单管理 + * + * @param bo 参数 + * @return 结果 + */ + Boolean updateByBo(WfFormManageBo bo); + + /** + * 批量删除表单管理信息 + * + * @param ids 主键 + * @return 结果 + */ + Boolean deleteByIds(Collection ids); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfNodeConfigService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfNodeConfigService.java new file mode 100644 index 000000000..5e64d64a5 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfNodeConfigService.java @@ -0,0 +1,56 @@ +package org.dromara.workflow.service; + +import org.dromara.workflow.domain.WfNodeConfig; +import org.dromara.workflow.domain.vo.WfNodeConfigVo; + +import java.util.Collection; +import java.util.List; + +/** + * 节点配置Service接口 + * + * @author may + * @date 2024-03-30 + */ +public interface IWfNodeConfigService { + + /** + * 查询节点配置 + * + * @param id 主键 + * @return 结果 + */ + WfNodeConfigVo queryById(Long id); + + /** + * 保存节点配置 + * + * @param list 参数 + * @return 结果 + */ + Boolean saveOrUpdate(List list); + + /** + * 批量删除节点配置信息 + * + * @param ids 主键 + * @return 结果 + */ + Boolean deleteByIds(Collection ids); + + /** + * 按照流程定义id删除 + * + * @param ids 流程定义id + * @return 结果 + */ + Boolean deleteByDefIds(Collection ids); + + /** + * 按照流程定义id查询 + * + * @param ids 流程定义id + * @return 结果 + */ + List selectByDefIds(Collection ids); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfTaskBackNodeService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfTaskBackNodeService.java new file mode 100644 index 000000000..97f940671 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfTaskBackNodeService.java @@ -0,0 +1,65 @@ +package org.dromara.workflow.service; + + +import org.dromara.workflow.domain.WfTaskBackNode; +import org.flowable.task.api.Task; + +import java.util.List; + +/** + * 节点驳回记录Service接口 + * + * @author may + * @date 2024-03-13 + */ +public interface IWfTaskBackNodeService { + + /** + * 记录审批节点 + * + * @param task 任务 + */ + void recordExecuteNode(Task task); + + /** + * 按流程实例id查询 + * + * @param processInstanceId 流程实例id + * @return 结果 + */ + List getListByInstanceId(String processInstanceId); + + /** + * 按照流程实例id,节点id查询 + * + * @param processInstanceId 流程实例id + * @param nodeId 节点id + * @return 结果 + */ + WfTaskBackNode getListByInstanceIdAndNodeId(String processInstanceId, String nodeId); + + /** + * 删除驳回后的节点 + * + * @param processInstanceId 流程实例id + * @param targetActivityId 节点id + * @return 结果 + */ + boolean deleteBackTaskNode(String processInstanceId, String targetActivityId); + + /** + * 按流程实例id删除 + * + * @param processInstanceId 流程实例id + * @return 结果 + */ + boolean deleteByInstanceId(String processInstanceId); + + /** + * 按流程实例id删除 + * + * @param processInstanceIds 流程实例id + * @return 结果 + */ + boolean deleteByInstanceIds(List processInstanceIds); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWorkflowUserService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWorkflowUserService.java new file mode 100644 index 000000000..22639d586 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWorkflowUserService.java @@ -0,0 +1,61 @@ +package org.dromara.workflow.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.system.domain.SysUserRole; +import org.dromara.system.domain.bo.SysUserBo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.workflow.domain.bo.SysUserMultiBo; +import org.dromara.workflow.domain.vo.TaskVo; + +import java.util.List; + +/** + * 工作流用户选人管理 服务层 + * + * @author may + */ +public interface IWorkflowUserService { + + /** + * 分页查询工作流选择加签人员 + * + * @param sysUserMultiBo 参数 + * @param pageQuery 分页 + * @return 结果 + */ + TableDataInfo getPageByAddMultiInstance(SysUserMultiBo sysUserMultiBo, PageQuery pageQuery); + + /** + * 查询工作流选择减签人员 + * + * @param taskId 任务id + * @return 结果 + */ + List getListByDeleteMultiInstance(String taskId); + + /** + * 按照用户id查询用户 + * + * @param userIds 用户id + * @return 结果 + */ + List getUserListByIds(List userIds); + + /** + * 按照角色id查询关联用户id + * + * @param roleIds 角色id + * @return 结果 + */ + List getUserRoleListByRoleIds(List roleIds); + + /** + * 分页查询用户 + * + * @param sysUserBo 参数 + * @param pageQuery 分页 + * @return 结果 + */ + TableDataInfo getPageByUserList(SysUserBo sysUserBo, PageQuery pageQuery); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActHiProcinstServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActHiProcinstServiceImpl.java new file mode 100644 index 000000000..06d607b4f --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActHiProcinstServiceImpl.java @@ -0,0 +1,51 @@ +package org.dromara.workflow.service.impl; + + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.RequiredArgsConstructor; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.workflow.domain.ActHiProcinst; +import org.dromara.workflow.mapper.ActHiProcinstMapper; +import org.dromara.workflow.service.IActHiProcinstService; +import org.springframework.stereotype.Service; + +import java.util.List; + + +/** + * 流程实例Service业务层处理 + * + * @author may + * @date 2023-07-22 + */ +@RequiredArgsConstructor +@Service +public class ActHiProcinstServiceImpl implements IActHiProcinstService { + + private final ActHiProcinstMapper baseMapper; + + /** + * 按照业务id查询 + * + * @param businessKeys 业务id + */ + @Override + public List selectByBusinessKeyIn(List businessKeys) { + return baseMapper.selectList(new LambdaQueryWrapper() + .in(ActHiProcinst::getBusinessKey, businessKeys) + .eq(TenantHelper.isEnable(), ActHiProcinst::getTenantId, TenantHelper.getTenantId())); + } + + /** + * 按照业务id查询 + * + * @param businessKey 业务id + */ + @Override + public ActHiProcinst selectByBusinessKey(String businessKey) { + return baseMapper.selectOne(new LambdaQueryWrapper() + .eq(ActHiProcinst::getBusinessKey, businessKey) + .eq(TenantHelper.isEnable(), ActHiProcinst::getTenantId, TenantHelper.getTenantId())); + + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActHiTaskinstServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActHiTaskinstServiceImpl.java new file mode 100644 index 000000000..5548f22f5 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActHiTaskinstServiceImpl.java @@ -0,0 +1,18 @@ +package org.dromara.workflow.service.impl; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.dromara.workflow.service.IActHiTaskinstService; + + +/** + * 流程历史任务Service业务层处理 + * + * @author may + * @date 2024-03-02 + */ +@RequiredArgsConstructor +@Service +public class ActHiTaskinstServiceImpl implements IActHiTaskinstService { + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActModelServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActModelServiceImpl.java new file mode 100644 index 000000000..cdbfd3c5d --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActModelServiceImpl.java @@ -0,0 +1,433 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Validator; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.core.util.ZipUtil; +import cn.hutool.json.JSONUtil; +import com.alibaba.excel.util.StringUtils; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.apache.batik.transcoder.TranscoderInput; +import org.apache.batik.transcoder.TranscoderOutput; +import org.apache.batik.transcoder.image.PNGTranscoder; +import org.apache.commons.io.IOUtils; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.workflow.common.constant.FlowConstant; +import org.dromara.workflow.domain.WfNodeConfig; +import org.dromara.workflow.domain.bo.ModelBo; +import org.dromara.workflow.domain.bo.WfDefinitionConfigBo; +import org.dromara.workflow.domain.vo.ModelVo; +import org.dromara.workflow.domain.vo.WfDefinitionConfigVo; +import org.dromara.workflow.service.IActModelService; +import org.dromara.workflow.service.IWfDefinitionConfigService; +import org.dromara.workflow.service.IWfNodeConfigService; +import org.dromara.workflow.utils.ModelUtils; +import org.dromara.workflow.utils.QueryUtils; +import org.flowable.bpmn.converter.BpmnXMLConverter; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.Process; +import org.flowable.bpmn.model.UserTask; +import org.flowable.engine.RepositoryService; +import org.flowable.engine.repository.*; +import org.flowable.validation.ValidationError; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +/** + * 模型管理 服务层实现 + * + * @author may + */ +@RequiredArgsConstructor +@Service +public class ActModelServiceImpl implements IActModelService { + + private final RepositoryService repositoryService; + private final IWfNodeConfigService iWfNodeConfigService; + private final IWfDefinitionConfigService iWfDefinitionConfigService; + + /** + * 分页查询模型 + * + * @param modelBo 模型参数 + * @return 返回分页列表 + */ + @Override + public TableDataInfo page(ModelBo modelBo, PageQuery pageQuery) { + ModelQuery query = QueryUtils.modelQuery(); + if (StringUtils.isNotBlank(modelBo.getName())) { + query.modelNameLike("%" + modelBo.getName() + "%"); + } + if (StringUtils.isNotBlank(modelBo.getKey())) { + query.modelKey(modelBo.getKey()); + } + if (StringUtils.isNotBlank(modelBo.getCategoryCode())) { + query.modelCategory(modelBo.getCategoryCode()); + } + query.orderByLastUpdateTime().desc(); + // 创建时间降序排列 + query.orderByCreateTime().desc(); + // 分页查询 + List modelList = query.listPage(pageQuery.getFirstNum(), pageQuery.getPageSize()); + // 总记录数 + long total = query.count(); + TableDataInfo build = TableDataInfo.build(); + build.setRows(modelList); + build.setTotal(total); + return build; + } + + /** + * 新增模型 + * + * @param modelBo 模型请求对象 + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean saveNewModel(ModelBo modelBo) { + try { + int version = 0; + String key = modelBo.getKey(); + String name = modelBo.getName(); + String description = modelBo.getDescription(); + String categoryCode = modelBo.getCategoryCode(); + String xml = modelBo.getXml(); + Model checkModel = QueryUtils.modelQuery().modelKey(key).singleResult(); + if (ObjectUtil.isNotNull(checkModel)) { + throw new ServiceException("模型key已存在!"); + } + //初始空的模型 + Model model = repositoryService.newModel(); + model.setKey(key); + model.setName(name); + model.setVersion(version); + model.setCategory(categoryCode); + model.setMetaInfo(description); + model.setTenantId(TenantHelper.getTenantId()); + //保存初始化的模型基本信息数据 + repositoryService.saveModel(model); + repositoryService.addModelEditorSource(model.getId(), StrUtil.utf8Bytes(xml)); + return true; + } catch (Exception e) { + e.printStackTrace(); + throw new ServiceException(e.getMessage()); + } + } + + /** + * 查询模型 + * + * @param id 模型id + * @return 模型数据 + */ + @Override + public ModelVo getInfo(String id) { + ModelVo modelVo = new ModelVo(); + Model model = repositoryService.getModel(id); + if (model != null) { + try { + byte[] modelEditorSource = repositoryService.getModelEditorSource(model.getId()); + modelVo.setXml(StrUtil.utf8Str(modelEditorSource)); + modelVo.setId(model.getId()); + modelVo.setKey(model.getKey()); + modelVo.setName(model.getName()); + modelVo.setCategoryCode(model.getCategory()); + modelVo.setDescription(model.getMetaInfo()); + return modelVo; + } catch (Exception e) { + throw new ServiceException(e.getMessage()); + } + } + return modelVo; + } + + /** + * 修改模型信息 + * + * @param modelBo 模型数据 + * @return 结果 + */ + @Override + public boolean update(ModelBo modelBo) { + try { + Model model = repositoryService.getModel(modelBo.getId()); + List list = QueryUtils.modelQuery().modelKey(modelBo.getKey()).list(); + list.stream().filter(e -> !e.getId().equals(model.getId())).findFirst().ifPresent(e -> { + throw new ServiceException("模型KEY已存在!"); + }); + model.setCategory(modelBo.getCategoryCode()); + model.setMetaInfo(modelBo.getDescription()); + repositoryService.saveModel(model); + } catch (Exception e) { + throw new ServiceException(e.getMessage()); + } + return true; + } + + /** + * 编辑模型XML + * + * @param modelBo 模型数据 + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean editModelXml(ModelBo modelBo) { + try { + String xml = modelBo.getXml(); + String svg = modelBo.getSvg(); + String modelId = modelBo.getId(); + String key = modelBo.getKey(); + String name = modelBo.getName(); + BpmnModel bpmnModel = ModelUtils.xmlToBpmnModel(xml); + ModelUtils.checkBpmnModel(bpmnModel); + Model model = repositoryService.getModel(modelId); + List list = QueryUtils.modelQuery().modelKey(key).list(); + list.stream().filter(e -> !e.getId().equals(model.getId())).findFirst().ifPresent(e -> { + throw new ServiceException("模型KEY已存在!"); + }); + // 校验key命名规范 + if (!Validator.isMatchRegex(FlowConstant.MODEL_KEY_PATTERN, key)) { + throw new ServiceException("模型标识KEY只能字符或者下划线开头!"); + } + model.setKey(key); + model.setName(name); + model.setVersion(model.getVersion() + 1); + repositoryService.saveModel(model); + repositoryService.addModelEditorSource(model.getId(), StrUtil.utf8Bytes(xml)); + // 转换图片 + InputStream svgStream = new ByteArrayInputStream(StrUtil.utf8Bytes(svg)); + TranscoderInput input = new TranscoderInput(svgStream); + + PNGTranscoder transcoder = new PNGTranscoder(); + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + TranscoderOutput output = new TranscoderOutput(outStream); + + transcoder.transcode(input, output); + final byte[] result = outStream.toByteArray(); + repositoryService.addModelEditorSourceExtra(model.getId(), result); + return true; + } catch (Exception e) { + e.printStackTrace(); + throw new ServiceException(e.getMessage()); + } + } + + /** + * 模型部署 + * + * @param id 模型id + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean modelDeploy(String id) { + try { + // 查询流程定义模型xml + byte[] xmlBytes = repositoryService.getModelEditorSource(id); + if (ArrayUtil.isEmpty(xmlBytes)) { + throw new ServiceException("模型数据为空,请先设计流程定义模型,再进行部署!"); + } + if (JSONUtil.isTypeJSON(IOUtils.toString(xmlBytes, StandardCharsets.UTF_8.toString()))) { + byte[] bytes = ModelUtils.bpmnJsonToXmlBytes(xmlBytes); + if (ArrayUtil.isEmpty(bytes)) { + throw new ServiceException("模型不能为空,请至少设计一条主线流程!"); + } + } + BpmnModel bpmnModel = ModelUtils.xmlToBpmnModel(xmlBytes); + // 校验模型 + ModelUtils.checkBpmnModel(bpmnModel); + List validationErrors = repositoryService.validateProcess(bpmnModel); + if (CollUtil.isNotEmpty(validationErrors)) { + String errorMsg = validationErrors.stream().map(ValidationError::getProblem).distinct().collect(Collectors.joining(",")); + throw new ServiceException(errorMsg); + } + // 查询模型的基本信息 + Model model = repositoryService.getModel(id); + ProcessDefinition processDefinition = QueryUtils.definitionQuery().processDefinitionKey(model.getKey()).latestVersion().singleResult(); + // xml资源的名称 ,对应act_ge_bytearray表中的name_字段 + String processName = model.getName() + ".bpmn20.xml"; + // 调用部署相关的api方法进行部署流程定义 + Deployment deployment = repositoryService.createDeployment() + // 部署名称 + .name(model.getName()) + // 部署标识key + .key(model.getKey()) + // 部署流程分类 + .category(model.getCategory()) + // bpmn20.xml资源 + .addBytes(processName, xmlBytes) + // 租户id + .tenantId(TenantHelper.getTenantId()) + .deploy(); + + // 更新 部署id 到流程定义模型数据表中 + model.setDeploymentId(deployment.getId()); + repositoryService.saveModel(model); + // 更新分类 + ProcessDefinition definition = QueryUtils.definitionQuery().deploymentId(deployment.getId()).singleResult(); + repositoryService.setProcessDefinitionCategory(definition.getId(), model.getCategory()); + //更新流程定义配置 + if (processDefinition != null) { + WfDefinitionConfigVo definitionVo = iWfDefinitionConfigService.getByDefId(processDefinition.getId()); + if (definitionVo != null) { + iWfDefinitionConfigService.deleteByDefIds(Collections.singletonList(processDefinition.getId())); + WfDefinitionConfigBo wfFormDefinition = new WfDefinitionConfigBo(); + wfFormDefinition.setDefinitionId(definition.getId()); + wfFormDefinition.setProcessKey(definition.getKey()); + wfFormDefinition.setTableName(definitionVo.getTableName()); + wfFormDefinition.setVersion(definition.getVersion()); + wfFormDefinition.setRemark(definitionVo.getRemark()); + iWfDefinitionConfigService.saveOrUpdate(wfFormDefinition); + } + } + //更新流程节点配置表单 + List userTasks = ModelUtils.getUserTaskFlowElements(definition.getId()); + UserTask applyUserTask = ModelUtils.getApplyUserTask(definition.getId()); + List wfNodeConfigList = new ArrayList<>(); + for (UserTask userTask : userTasks) { + if (StringUtils.isNotBlank(userTask.getFormKey()) && userTask.getFormKey().contains(StrUtil.COLON)) { + WfNodeConfig wfNodeConfig = new WfNodeConfig(); + wfNodeConfig.setNodeId(userTask.getId()); + wfNodeConfig.setNodeName(userTask.getName()); + wfNodeConfig.setDefinitionId(definition.getId()); + String[] split = userTask.getFormKey().split(StrUtil.COLON); + wfNodeConfig.setFormType(split[0]); + wfNodeConfig.setFormId(Long.valueOf(split[1])); + wfNodeConfig.setApplyUserTask(applyUserTask.getId().equals(userTask.getId()) ? FlowConstant.TRUE : FlowConstant.FALSE); + wfNodeConfigList.add(wfNodeConfig); + } + } + if (CollUtil.isNotEmpty(wfNodeConfigList)) { + iWfNodeConfigService.saveOrUpdate(wfNodeConfigList); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + throw new ServiceException(e.getMessage()); + } + } + + /** + * 导出模型zip压缩包 + * + * @param modelIds 模型id + * @param response 相应 + */ + @Override + public void exportZip(List modelIds, HttpServletResponse response) { + ZipOutputStream zos = null; + try { + zos = ZipUtil.getZipOutputStream(response.getOutputStream(), StandardCharsets.UTF_8); + // 压缩包文件名 + String zipName = "模型不存在"; + // 查询模型基本信息 + for (String modelId : modelIds) { + Model model = repositoryService.getModel(modelId); + byte[] xmlBytes = repositoryService.getModelEditorSource(modelId); + if (ObjectUtil.isNotNull(model)) { + if (JSONUtil.isTypeJSON(IOUtils.toString(xmlBytes, StandardCharsets.UTF_8.toString())) && ArrayUtil.isEmpty(ModelUtils.bpmnJsonToXmlBytes(xmlBytes))) { + zipName = "模型不能为空,请至少设计一条主线流程!"; + zos.putNextEntry(new ZipEntry(zipName + ".txt")); + zos.write(zipName.getBytes(StandardCharsets.UTF_8)); + } else if (ArrayUtil.isEmpty(xmlBytes)) { + zipName = "模型数据为空,请先设计流程定义模型,再进行部署!"; + zos.putNextEntry(new ZipEntry(zipName + ".txt")); + zos.write(zipName.getBytes(StandardCharsets.UTF_8)); + } else { + String fileName = model.getName() + "-" + model.getKey(); + // 压缩包文件名 + zipName = fileName + ".zip"; + // 将xml添加到压缩包中(指定xml文件名:请假流程.bpmn20.xml + zos.putNextEntry(new ZipEntry(fileName + ".bpmn20.xml")); + zos.write(xmlBytes); + } + } + } + response.setHeader("Content-Disposition", + "attachment; filename=" + URLEncoder.encode(zipName, StandardCharsets.UTF_8) + ".zip"); + // 刷出响应流 + response.flushBuffer(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (zos != null) { + try { + zos.closeEntry(); + zos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + /** + * 复制模型 + * + * @param modelBo 模型数据 + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean copyModel(ModelBo modelBo) { + try { + String key = modelBo.getKey(); + if (StringUtils.isNotBlank(key)) { + // 查询模型 + Model model = repositoryService.createModelQuery().modelId(modelBo.getId()).singleResult(); + if (ObjectUtil.isNotNull(model)) { + byte[] modelEditorSource = repositoryService.getModelEditorSource(model.getId()); + List list = QueryUtils.modelQuery().modelKey(key).list(); + if (CollUtil.isNotEmpty(list)) { + throw new ServiceException("模型KEY已存在!"); + } + // 校验key命名规范 + if (!Validator.isMatchRegex(FlowConstant.MODEL_KEY_PATTERN, key)) { + throw new ServiceException("模型标识KEY只能字符或者下划线开头!"); + } + // 复制模型数据 + Model newModel = repositoryService.newModel(); + newModel.setKey(modelBo.getKey()); + newModel.setName(modelBo.getName()); + newModel.setCategory(modelBo.getCategoryCode()); + newModel.setVersion(1); + newModel.setMetaInfo(modelBo.getDescription()); + newModel.setTenantId(TenantHelper.getTenantId()); + String xml = StrUtil.utf8Str(modelEditorSource); + BpmnModel bpmnModel = ModelUtils.xmlToBpmnModel(xml); + Process mainProcess = bpmnModel.getMainProcess(); + mainProcess.setId(modelBo.getKey()); + mainProcess.setName(modelBo.getName()); + byte[] xmlBytes = new BpmnXMLConverter().convertToXML(bpmnModel); + repositoryService.saveModel(newModel); + repositoryService.addModelEditorSource(newModel.getId(), xmlBytes); + } + } + } catch (Exception e) { + throw new ServiceException(e.getMessage()); + } + return true; + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessDefinitionServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessDefinitionServiceImpl.java new file mode 100644 index 000000000..468e3978e --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessDefinitionServiceImpl.java @@ -0,0 +1,443 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.codec.Base64; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import org.apache.commons.io.IOUtils; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.workflow.common.constant.FlowConstant; +import org.dromara.workflow.domain.WfCategory; +import org.dromara.workflow.domain.WfDefinitionConfig; +import org.dromara.workflow.domain.WfNodeConfig; +import org.dromara.workflow.domain.bo.ProcessDefinitionBo; +import org.dromara.workflow.domain.bo.WfDefinitionConfigBo; +import org.dromara.workflow.domain.vo.ProcessDefinitionVo; +import org.dromara.workflow.domain.vo.WfDefinitionConfigVo; +import org.dromara.workflow.mapper.WfDefinitionConfigMapper; +import org.dromara.workflow.service.IActProcessDefinitionService; +import org.dromara.workflow.service.IWfCategoryService; +import org.dromara.workflow.service.IWfDefinitionConfigService; +import org.dromara.workflow.service.IWfNodeConfigService; +import org.dromara.workflow.utils.ModelUtils; +import org.dromara.workflow.utils.QueryUtils; +import org.flowable.bpmn.model.UserTask; +import org.flowable.engine.ProcessMigrationService; +import org.flowable.engine.RepositoryService; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.impl.bpmn.deployer.ResourceNameUtil; +import org.flowable.engine.repository.*; +import org.flowable.task.api.history.HistoricTaskInstance; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +/** + * 流程定义 服务层实现 + * + * @author may + */ +@RequiredArgsConstructor +@Service +public class ActProcessDefinitionServiceImpl implements IActProcessDefinitionService { + + private final RepositoryService repositoryService; + private final ProcessMigrationService processMigrationService; + private final IWfCategoryService wfCategoryService; + private final IWfDefinitionConfigService iWfDefinitionConfigService; + private final WfDefinitionConfigMapper wfDefinitionConfigMapper; + private final IWfNodeConfigService iWfNodeConfigService; + + /** + * 分页查询 + * + * @param bo 参数 + * @return 返回分页列表 + */ + @Override + public TableDataInfo page(ProcessDefinitionBo bo, PageQuery pageQuery) { + ProcessDefinitionQuery query = QueryUtils.definitionQuery(); + if (StringUtils.isNotEmpty(bo.getKey())) { + query.processDefinitionKey(bo.getKey()); + } + if (StringUtils.isNotEmpty(bo.getCategoryCode())) { + query.processDefinitionCategory(bo.getCategoryCode()); + } + if (StringUtils.isNotEmpty(bo.getName())) { + query.processDefinitionNameLike("%" + bo.getName() + "%"); + } + query.orderByDeploymentId().desc(); + // 分页查询 + List processDefinitionVoList = new ArrayList<>(); + List definitionList = query.latestVersion().listPage(pageQuery.getFirstNum(), pageQuery.getPageSize()); + List deploymentList = null; + if (CollUtil.isNotEmpty(definitionList)) { + List deploymentIds = StreamUtils.toList(definitionList, ProcessDefinition::getDeploymentId); + deploymentList = QueryUtils.deploymentQuery(deploymentIds).list(); + } + if (CollUtil.isNotEmpty(definitionList)) { + List ids = StreamUtils.toList(definitionList, ProcessDefinition::getId); + List wfDefinitionConfigVos = iWfDefinitionConfigService.queryList(ids); + for (ProcessDefinition processDefinition : definitionList) { + ProcessDefinitionVo processDefinitionVo = BeanUtil.toBean(processDefinition, ProcessDefinitionVo.class); + if (CollUtil.isNotEmpty(deploymentList)) { + // 部署时间 + deploymentList.stream().filter(e -> e.getId().equals(processDefinition.getDeploymentId())).findFirst().ifPresent(e -> { + processDefinitionVo.setDeploymentTime(e.getDeploymentTime()); + }); + } + if (CollUtil.isNotEmpty(wfDefinitionConfigVos)) { + wfDefinitionConfigVos.stream().filter(e -> e.getDefinitionId().equals(processDefinition.getId())).findFirst().ifPresent(processDefinitionVo::setWfDefinitionConfigVo); + } + processDefinitionVoList.add(processDefinitionVo); + } + } + // 总记录数 + long total = query.count(); + TableDataInfo build = TableDataInfo.build(); + build.setRows(processDefinitionVoList); + build.setTotal(total); + return build; + } + + /** + * 查询历史流程定义列表 + * + * @param key 流程定义key + */ + @Override + public List getListByKey(String key) { + List processDefinitionVoList = new ArrayList<>(); + ProcessDefinitionQuery query = QueryUtils.definitionQuery(); + List definitionList = query.processDefinitionKey(key).list(); + List deploymentList = null; + if (CollUtil.isNotEmpty(definitionList)) { + List deploymentIds = StreamUtils.toList(definitionList, ProcessDefinition::getDeploymentId); + deploymentList = QueryUtils.deploymentQuery(deploymentIds).list(); + } + if (CollUtil.isNotEmpty(definitionList)) { + List ids = StreamUtils.toList(definitionList, ProcessDefinition::getId); + List wfDefinitionConfigVos = iWfDefinitionConfigService.queryList(ids); + for (ProcessDefinition processDefinition : definitionList) { + ProcessDefinitionVo processDefinitionVo = BeanUtil.toBean(processDefinition, ProcessDefinitionVo.class); + if (CollUtil.isNotEmpty(deploymentList)) { + // 部署时间 + deploymentList.stream().filter(e -> e.getId().equals(processDefinition.getDeploymentId())).findFirst().ifPresent(e -> { + processDefinitionVo.setDeploymentTime(e.getDeploymentTime()); + }); + if (CollUtil.isNotEmpty(wfDefinitionConfigVos)) { + wfDefinitionConfigVos.stream().filter(e -> e.getDefinitionId().equals(processDefinition.getId())).findFirst().ifPresent(processDefinitionVo::setWfDefinitionConfigVo); + } + } + processDefinitionVoList.add(processDefinitionVo); + } + } + return CollectionUtil.reverse(processDefinitionVoList); + } + + /** + * 查看流程定义图片 + * + * @param processDefinitionId 流程定义id + */ + @SneakyThrows + @Override + public String definitionImage(String processDefinitionId) { + InputStream inputStream = repositoryService.getProcessDiagram(processDefinitionId); + return Base64.encode(IOUtils.toByteArray(inputStream)); + } + + /** + * 查看流程定义xml文件 + * + * @param processDefinitionId 流程定义id + */ + @Override + public String definitionXml(String processDefinitionId) { + StringBuilder xml = new StringBuilder(); + ProcessDefinition processDefinition = repositoryService.getProcessDefinition(processDefinitionId); + InputStream inputStream; + try { + inputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getResourceName()); + xml.append(IOUtils.toString(inputStream, StandardCharsets.UTF_8)); + } catch (IOException e) { + e.printStackTrace(); + } + return xml.toString(); + } + + /** + * 删除流程定义 + * + * @param deploymentIds 部署id + * @param processDefinitionIds 流程定义id + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean deleteDeployment(List deploymentIds, List processDefinitionIds) { + try { + List historicProcessInstances = QueryUtils.hisInstanceQuery().deploymentIdIn(deploymentIds).list(); + if (CollectionUtil.isNotEmpty(historicProcessInstances)) { + Set defIds = StreamUtils.toSet(historicProcessInstances, HistoricProcessInstance::getProcessDefinitionId); + List processDefinitions = QueryUtils.definitionQuery().processDefinitionIds(defIds).list(); + if (CollUtil.isNotEmpty(processDefinitions)) { + Set keys = StreamUtils.toSet(processDefinitions, ProcessDefinition::getKey); + throw new ServiceException("当前【" + String.join(",", keys) + "】流程定义已被使用不可删除!"); + } + } + //删除流程定义 + for (String deploymentId : deploymentIds) { + repositoryService.deleteDeployment(deploymentId); + } + //删除流程定义配置 + iWfDefinitionConfigService.deleteByDefIds(processDefinitionIds); + //删除节点配置 + iWfNodeConfigService.deleteByDefIds(processDefinitionIds); + return true; + } catch (Exception e) { + e.printStackTrace(); + throw new ServiceException(e.getMessage()); + } + } + + /** + * 激活或者挂起流程定义 + * + * @param processDefinitionId 流程定义id + */ + @Override + public boolean updateDefinitionState(String processDefinitionId) { + try { + ProcessDefinition processDefinition = QueryUtils.definitionQuery() + .processDefinitionId(processDefinitionId).singleResult(); + //将当前为挂起状态更新为激活状态 + //参数说明:参数1:流程定义id,参数2:是否激活(true是否级联对应流程实例,激活了则对应流程实例都可以审批), + //参数3:什么时候激活,如果为null则立即激活,如果为具体时间则到达此时间后激活 + if (processDefinition.isSuspended()) { + repositoryService.activateProcessDefinitionById(processDefinitionId, true, null); + } else { + repositoryService.suspendProcessDefinitionById(processDefinitionId, true, null); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + throw new ServiceException("操作失败:" + e.getMessage()); + } + } + + /** + * 迁移流程定义 + * + * @param currentProcessDefinitionId 当前流程定义id + * @param fromProcessDefinitionId 需要迁移到的流程定义id + */ + + @Override + public boolean migrationDefinition(String currentProcessDefinitionId, String fromProcessDefinitionId) { + try { + // 迁移验证 + boolean migrationValid = processMigrationService.createProcessInstanceMigrationBuilder() + .migrateToProcessDefinition(currentProcessDefinitionId) + .validateMigrationOfProcessInstances(fromProcessDefinitionId) + .isMigrationValid(); + if (!migrationValid) { + throw new ServiceException("流程定义差异过大无法迁移,请修改流程图"); + } + // 已结束的流程实例不会迁移 + processMigrationService.createProcessInstanceMigrationBuilder() + .migrateToProcessDefinition(currentProcessDefinitionId) + .migrateProcessInstances(fromProcessDefinitionId); + return true; + } catch (Exception e) { + throw new ServiceException(e.getMessage()); + } + } + + /** + * 流程定义转换为模型 + * + * @param processDefinitionId 流程定义id + */ + @Override + public boolean convertToModel(String processDefinitionId) { + ProcessDefinition pd = QueryUtils.definitionQuery() + .processDefinitionId(processDefinitionId).singleResult(); + InputStream inputStream = repositoryService.getResourceAsStream(pd.getDeploymentId(), pd.getResourceName()); + ModelQuery query = QueryUtils.modelQuery(); + Model model = query.modelKey(pd.getKey()).singleResult(); + try { + if (ObjectUtil.isNotNull(model)) { + repositoryService.addModelEditorSource(model.getId(), IoUtil.readBytes(inputStream)); + } else { + Model modelData = repositoryService.newModel(); + modelData.setKey(pd.getKey()); + modelData.setName(pd.getName()); + modelData.setTenantId(pd.getTenantId()); + repositoryService.saveModel(modelData); + repositoryService.addModelEditorSource(modelData.getId(), IoUtil.readBytes(inputStream)); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + throw new ServiceException(e.getMessage()); + } + } + + /** + * 通过zip或xml部署流程定义 + * + * @param file 文件 + * @param categoryCode 分类 + */ + @SneakyThrows + @Override + @Transactional(rollbackFor = Exception.class) + public void deployByFile(MultipartFile file, String categoryCode) { + + WfCategory wfCategory = wfCategoryService.queryByCategoryCode(categoryCode); + if (wfCategory == null) { + throw new ServiceException("流程分类不存在"); + } + // 文件后缀名 + String suffix = FileUtil.extName(file.getOriginalFilename()); + InputStream inputStream = file.getInputStream(); + if (FlowConstant.ZIP.equalsIgnoreCase(suffix)) { + ZipInputStream zipInputStream = null; + try { + zipInputStream = new ZipInputStream(inputStream); + ZipEntry zipEntry; + while ((zipEntry = zipInputStream.getNextEntry()) != null) { + String filename = zipEntry.getName(); + String[] splitFilename = filename.substring(0, filename.lastIndexOf(".")).split("-"); + //流程名称 + String processName = splitFilename[0]; + //流程key + String processKey = splitFilename[1]; + ProcessDefinition oldProcessDefinition = QueryUtils.definitionQuery().processDefinitionKey(processKey).latestVersion().singleResult(); + DeploymentBuilder builder = repositoryService.createDeployment(); + Deployment deployment = builder.addInputStream(filename, zipInputStream) + .tenantId(TenantHelper.getTenantId()) + .name(processName).key(processKey).category(categoryCode).deploy(); + ProcessDefinition definition = QueryUtils.definitionQuery().deploymentId(deployment.getId()).singleResult(); + repositoryService.setProcessDefinitionCategory(definition.getId(), categoryCode); + setWfConfig(oldProcessDefinition, definition); + zipInputStream.closeEntry(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } finally { + if (zipInputStream != null) { + zipInputStream.close(); + } + } + //初始化配置数据(demo使用,不用可删除) + initWfDefConfig(); + } else { + String originalFilename = file.getOriginalFilename(); + String bpmnResourceSuffix = ResourceNameUtil.BPMN_RESOURCE_SUFFIXES[0]; + if (originalFilename.contains(bpmnResourceSuffix)) { + // 文件名 = 流程名称-流程key + String[] splitFilename = originalFilename.substring(0, originalFilename.lastIndexOf(".")).split("-"); + if (splitFilename.length < 2) { + throw new ServiceException("文件名 = 流程名称-流程KEY"); + } + //流程名称 + String processName = splitFilename[0]; + //流程key + String processKey = splitFilename[1]; + ProcessDefinition oldProcessDefinition = QueryUtils.definitionQuery().processDefinitionKey(processKey).latestVersion().singleResult(); + DeploymentBuilder builder = repositoryService.createDeployment(); + Deployment deployment = builder.addInputStream(originalFilename, inputStream) + .tenantId(TenantHelper.getTenantId()) + .name(processName).key(processKey).category(categoryCode).deploy(); + // 更新分类 + ProcessDefinition definition = QueryUtils.definitionQuery().deploymentId(deployment.getId()).singleResult(); + repositoryService.setProcessDefinitionCategory(definition.getId(), categoryCode); + setWfConfig(oldProcessDefinition, definition); + } else { + throw new ServiceException("文件类型上传错误!"); + } + } + + } + + /** + * 初始化配置数据(demo使用,不用可删除) + */ + private void initWfDefConfig() { + List wfDefinitionConfigs = wfDefinitionConfigMapper.selectList(); + if (CollUtil.isEmpty(wfDefinitionConfigs)) { + ProcessDefinition processDefinition = QueryUtils.definitionQuery().processDefinitionKey("leave1").latestVersion().singleResult(); + if (processDefinition != null) { + WfDefinitionConfigBo wfFormDefinition = new WfDefinitionConfigBo(); + wfFormDefinition.setDefinitionId(processDefinition.getId()); + wfFormDefinition.setProcessKey(processDefinition.getKey()); + wfFormDefinition.setTableName("test_leave"); + wfFormDefinition.setVersion(processDefinition.getVersion()); + iWfDefinitionConfigService.saveOrUpdate(wfFormDefinition); + } + } + + } + + /** + * 设置表单内容 + * + * @param oldProcessDefinition 部署前最新流程定义 + * @param definition 部署后最新流程定义 + */ + private void setWfConfig(ProcessDefinition oldProcessDefinition, ProcessDefinition definition) { + //更新流程定义表单 + if (oldProcessDefinition != null) { + WfDefinitionConfigVo definitionVo = iWfDefinitionConfigService.getByDefId(oldProcessDefinition.getId()); + if (definitionVo != null) { + iWfDefinitionConfigService.deleteByDefIds(Collections.singletonList(oldProcessDefinition.getId())); + WfDefinitionConfigBo wfFormDefinition = new WfDefinitionConfigBo(); + wfFormDefinition.setDefinitionId(definition.getId()); + wfFormDefinition.setProcessKey(definition.getKey()); + wfFormDefinition.setTableName(definitionVo.getTableName()); + wfFormDefinition.setVersion(definition.getVersion()); + wfFormDefinition.setRemark(definitionVo.getRemark()); + iWfDefinitionConfigService.saveOrUpdate(wfFormDefinition); + } + } + //更新流程节点配置表单 + List userTasks = ModelUtils.getUserTaskFlowElements(definition.getId()); + UserTask applyUserTask = ModelUtils.getApplyUserTask(definition.getId()); + List wfNodeConfigList = new ArrayList<>(); + for (UserTask userTask : userTasks) { + if (StringUtils.isNotBlank(userTask.getFormKey()) && userTask.getFormKey().contains(StrUtil.COLON)) { + WfNodeConfig wfNodeConfig = new WfNodeConfig(); + wfNodeConfig.setNodeId(userTask.getId()); + wfNodeConfig.setNodeName(userTask.getName()); + wfNodeConfig.setDefinitionId(definition.getId()); + String[] split = userTask.getFormKey().split(StrUtil.COLON); + wfNodeConfig.setFormType(split[0]); + wfNodeConfig.setFormId(Long.valueOf(split[1])); + wfNodeConfig.setApplyUserTask(applyUserTask.getId().equals(userTask.getId()) ? FlowConstant.TRUE : FlowConstant.FALSE); + wfNodeConfigList.add(wfNodeConfig); + } + } + if (CollUtil.isNotEmpty(wfNodeConfigList)) { + iWfNodeConfigService.saveOrUpdate(wfNodeConfigList); + } + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java new file mode 100644 index 000000000..9af37f633 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java @@ -0,0 +1,720 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.codec.Base64; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.IOUtils; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.workflow.common.constant.FlowConstant; +import org.dromara.workflow.common.enums.BusinessStatusEnum; +import org.dromara.workflow.common.enums.TaskStatusEnum; +import org.dromara.workflow.domain.ActHiProcinst; +import org.dromara.workflow.domain.bo.ProcessInstanceBo; +import org.dromara.workflow.domain.bo.ProcessInvalidBo; +import org.dromara.workflow.domain.bo.TaskUrgingBo; +import org.dromara.workflow.domain.vo.*; +import org.dromara.workflow.flowable.CustomDefaultProcessDiagramGenerator; +import org.dromara.workflow.flowable.cmd.DeleteExecutionCmd; +import org.dromara.workflow.flowable.cmd.ExecutionChildByExecutionIdCmd; +import org.dromara.workflow.flowable.strategy.FlowEventStrategy; +import org.dromara.workflow.flowable.strategy.FlowProcessEventHandler; +import org.dromara.workflow.service.IActHiProcinstService; +import org.dromara.workflow.service.IActProcessInstanceService; +import org.dromara.workflow.service.IWfNodeConfigService; +import org.dromara.workflow.service.IWfTaskBackNodeService; +import org.dromara.workflow.utils.QueryUtils; +import org.dromara.workflow.utils.WorkflowUtils; +import org.flowable.bpmn.model.*; +import org.flowable.engine.*; +import org.flowable.engine.history.HistoricActivityInstance; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.history.HistoricProcessInstanceQuery; +import org.flowable.engine.impl.persistence.entity.ExecutionEntity; +import org.flowable.engine.repository.ProcessDefinition; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.engine.runtime.ProcessInstanceQuery; +import org.flowable.engine.task.Attachment; +import org.flowable.engine.task.Comment; +import org.flowable.task.api.Task; +import org.flowable.task.api.history.HistoricTaskInstance; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.awt.*; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 流程实例 服务层实现 + * + * @author may + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class ActProcessInstanceServiceImpl implements IActProcessInstanceService { + + private final RepositoryService repositoryService; + private final RuntimeService runtimeService; + private final HistoryService historyService; + private final TaskService taskService; + private final IActHiProcinstService actHiProcinstService; + private final ManagementService managementService; + private final FlowEventStrategy flowEventStrategy; + private final IWfTaskBackNodeService iWfTaskBackNodeService; + private final IWfNodeConfigService iWfNodeConfigService; + + @Value("${flowable.activity-font-name}") + private String activityFontName; + + @Value("${flowable.label-font-name}") + private String labelFontName; + + @Value("${flowable.annotation-font-name}") + private String annotationFontName; + + /** + * 分页查询正在运行的流程实例 + * + * @param bo 参数 + */ + @Override + public TableDataInfo getPageByRunning(ProcessInstanceBo bo, PageQuery pageQuery) { + List list = new ArrayList<>(); + ProcessInstanceQuery query = QueryUtils.instanceQuery(); + if (StringUtils.isNotBlank(bo.getName())) { + query.processInstanceNameLikeIgnoreCase("%" + bo.getName() + "%"); + } + if (StringUtils.isNotBlank(bo.getKey())) { + query.processDefinitionKey(bo.getKey()); + } + if (StringUtils.isNotBlank(bo.getStartUserId())) { + query.startedBy(bo.getStartUserId()); + } + if (StringUtils.isNotBlank(bo.getBusinessKey())) { + query.processInstanceBusinessKey(bo.getBusinessKey()); + } + if (StringUtils.isNotBlank(bo.getCategoryCode())) { + query.processDefinitionCategory(bo.getCategoryCode()); + } + query.orderByStartTime().desc(); + List processInstances = query.listPage(pageQuery.getFirstNum(), pageQuery.getPageSize()); + for (ProcessInstance processInstance : processInstances) { + ProcessInstanceVo processInstanceVo = BeanUtil.toBean(processInstance, ProcessInstanceVo.class); + processInstanceVo.setIsSuspended(processInstance.isSuspended()); + processInstanceVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(processInstance.getBusinessStatus())); + list.add(processInstanceVo); + } + if (CollUtil.isNotEmpty(list)) { + List processDefinitionIds = StreamUtils.toList(list, ProcessInstanceVo::getProcessDefinitionId); + List wfNodeConfigVoList = iWfNodeConfigService.selectByDefIds(processDefinitionIds); + for (ProcessInstanceVo processInstanceVo : list) { + if (CollUtil.isNotEmpty(wfNodeConfigVoList)) { + wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(processInstanceVo.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(processInstanceVo::setWfNodeConfigVo); + } + } + } + long count = query.count(); + TableDataInfo build = TableDataInfo.build(); + build.setRows(list); + build.setTotal(count); + return build; + } + + /** + * 分页查询已结束的流程实例 + * + * @param bo 参数 + */ + @Override + public TableDataInfo getPageByFinish(ProcessInstanceBo bo, PageQuery pageQuery) { + List list = new ArrayList<>(); + HistoricProcessInstanceQuery query = QueryUtils.hisInstanceQuery() + .finished().orderByProcessInstanceEndTime().desc(); + if (StringUtils.isNotEmpty(bo.getName())) { + query.processInstanceNameLikeIgnoreCase("%" + bo.getName() + "%"); + } + if (StringUtils.isNotBlank(bo.getKey())) { + query.processDefinitionKey(bo.getKey()); + } + if (StringUtils.isNotEmpty(bo.getStartUserId())) { + query.startedBy(bo.getStartUserId()); + } + if (StringUtils.isNotBlank(bo.getBusinessKey())) { + query.processInstanceBusinessKey(bo.getBusinessKey()); + } + if (StringUtils.isNotBlank(bo.getCategoryCode())) { + query.processDefinitionCategory(bo.getCategoryCode()); + } + List historicProcessInstances = query.listPage(pageQuery.getFirstNum(), pageQuery.getPageSize()); + for (HistoricProcessInstance historicProcessInstance : historicProcessInstances) { + ProcessInstanceVo processInstanceVo = BeanUtil.toBean(historicProcessInstance, ProcessInstanceVo.class); + processInstanceVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(historicProcessInstance.getBusinessStatus())); + list.add(processInstanceVo); + } + if (CollUtil.isNotEmpty(list)) { + List processDefinitionIds = StreamUtils.toList(list, ProcessInstanceVo::getProcessDefinitionId); + List wfNodeConfigVoList = iWfNodeConfigService.selectByDefIds(processDefinitionIds); + for (ProcessInstanceVo processInstanceVo : list) { + if (CollUtil.isNotEmpty(wfNodeConfigVoList)) { + wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(processInstanceVo.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(processInstanceVo::setWfNodeConfigVo); + } + } + } + long count = query.count(); + TableDataInfo build = TableDataInfo.build(); + build.setRows(list); + build.setTotal(count); + return build; + } + + /** + * 通过流程实例id获取历史流程图 + * + * @param processInstanceId 流程实例id + */ + @SneakyThrows + @Override + public String getHistoryImage(String processInstanceId) { + String processDefinitionId; + // 获取当前的流程实例 + ProcessInstance processInstance = QueryUtils.instanceQuery(processInstanceId).singleResult(); + // 如果流程已经结束,则得到结束节点 + if (Objects.isNull(processInstance)) { + HistoricProcessInstance pi = QueryUtils.hisInstanceQuery(processInstanceId).singleResult(); + processDefinitionId = pi.getProcessDefinitionId(); + } else { + // 根据流程实例ID获得当前处于活动状态的ActivityId合集 + ProcessInstance pi = QueryUtils.instanceQuery(processInstanceId).singleResult(); + processDefinitionId = pi.getProcessDefinitionId(); + } + + // 获得活动的节点 + List highLightedFlowList = QueryUtils.hisActivityInstanceQuery(processInstanceId).orderByHistoricActivityInstanceStartTime().asc().list(); + + List highLightedFlows = new ArrayList<>(); + List highLightedNodes = new ArrayList<>(); + //高亮 + for (HistoricActivityInstance tempActivity : highLightedFlowList) { + if (FlowConstant.SEQUENCE_FLOW.equals(tempActivity.getActivityType())) { + //高亮线 + highLightedFlows.add(tempActivity.getActivityId()); + } else { + //高亮节点 + if (tempActivity.getEndTime() == null) { + highLightedNodes.add(Color.RED.toString() + tempActivity.getActivityId()); + } else { + highLightedNodes.add(tempActivity.getActivityId()); + } + } + } + List highLightedNodeList = new ArrayList<>(); + //运行中的节点 + List redNodeCollect = StreamUtils.filter(highLightedNodes, e -> e.contains(Color.RED.toString())); + //排除与运行中相同的节点 + for (String nodeId : highLightedNodes) { + if (!nodeId.contains(Color.RED.toString()) && !redNodeCollect.contains(Color.RED + nodeId)) { + highLightedNodeList.add(nodeId); + } + } + highLightedNodeList.addAll(redNodeCollect); + BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId); + CustomDefaultProcessDiagramGenerator diagramGenerator = new CustomDefaultProcessDiagramGenerator(); + InputStream inputStream = diagramGenerator.generateDiagram(bpmnModel, "png", highLightedNodeList, highLightedFlows, activityFontName, labelFontName, annotationFontName, null, 1.0, true); + return Base64.encode(IOUtils.toByteArray(inputStream)); + } + + /** + * 通过流程实例id获取历史流程图运行中,历史等节点 + * + * @param processInstanceId 流程实例id + */ + @Override + public Map getHistoryList(String processInstanceId) { + Map map = new HashMap<>(); + List> taskList = new ArrayList<>(); + HistoricProcessInstance historicProcessInstance = QueryUtils.hisInstanceQuery(processInstanceId).singleResult(); + StringBuilder xml = new StringBuilder(); + ProcessDefinition processDefinition = repositoryService.getProcessDefinition(historicProcessInstance.getProcessDefinitionId()); + // 获取节点 + List highLightedFlowList = QueryUtils.hisActivityInstanceQuery(processInstanceId).orderByHistoricActivityInstanceStartTime().asc().list(); + for (HistoricActivityInstance tempActivity : highLightedFlowList) { + Map task = new HashMap<>(); + if (!FlowConstant.SEQUENCE_FLOW.equals(tempActivity.getActivityType()) && + !FlowConstant.PARALLEL_GATEWAY.equals(tempActivity.getActivityType()) && + !FlowConstant.EXCLUSIVE_GATEWAY.equals(tempActivity.getActivityType()) && + !FlowConstant.INCLUSIVE_GATEWAY.equals(tempActivity.getActivityType()) + ) { + task.put("key", tempActivity.getActivityId()); + task.put("completed", tempActivity.getEndTime() != null); + task.put("activityType", tempActivity.getActivityType()); + taskList.add(task); + } + } + ProcessInstance processInstance = QueryUtils.instanceQuery(processInstanceId).singleResult(); + if (processInstance != null) { + taskList = taskList.stream().filter(e -> !e.get("activityType").equals(FlowConstant.END_EVENT)).collect(Collectors.toList()); + } + //查询出运行中节点 + List> runtimeNodeList = taskList.stream().filter(e -> !(Boolean) e.get("completed")).collect(Collectors.toList()); + if (CollUtil.isNotEmpty(runtimeNodeList)) { + Iterator> iterator = taskList.iterator(); + while (iterator.hasNext()) { + Map next = iterator.next(); + runtimeNodeList.stream().filter(t -> t.get("key").equals(next.get("key")) && (Boolean) next.get("completed")).findFirst().ifPresent(t -> iterator.remove()); + } + } + map.put("taskList", taskList); + List historyTaskList = getHistoryTaskList(processInstanceId); + map.put("historyList", historyTaskList); + InputStream inputStream; + try { + inputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getResourceName()); + xml.append(IOUtils.toString(inputStream, String.valueOf(StandardCharsets.UTF_8))); + map.put("xml", xml.toString()); + } catch (IOException e) { + e.printStackTrace(); + } + return map; + } + + /** + * 获取历史任务节点信息 + * + * @param processInstanceId 流程实例id + */ + private List getHistoryTaskList(String processInstanceId) { + //查询任务办理记录 + List list = QueryUtils.hisTaskInstanceQuery(processInstanceId).orderByHistoricTaskInstanceEndTime().desc().list(); + list = StreamUtils.sorted(list, Comparator.comparing(HistoricTaskInstance::getEndTime, Comparator.nullsFirst(Date::compareTo)).reversed()); + List actHistoryInfoVoList = new ArrayList<>(); + for (HistoricTaskInstance historicTaskInstance : list) { + ActHistoryInfoVo actHistoryInfoVo = new ActHistoryInfoVo(); + BeanUtils.copyProperties(historicTaskInstance, actHistoryInfoVo); + actHistoryInfoVo.setAssignee(StringUtils.isNotBlank(historicTaskInstance.getAssignee()) ? Long.valueOf(historicTaskInstance.getAssignee()) : null); + actHistoryInfoVo.setStatus(actHistoryInfoVo.getEndTime() == null ? "待处理" : "已处理"); + if (ObjectUtil.isNotEmpty(historicTaskInstance.getDurationInMillis())) { + actHistoryInfoVo.setRunDuration(getDuration(historicTaskInstance.getDurationInMillis())); + } + actHistoryInfoVoList.add(actHistoryInfoVo); + } + List historyInfoVoList = new ArrayList<>(); + Map> groupByKey = StreamUtils.groupByKey(actHistoryInfoVoList, ActHistoryInfoVo::getTaskDefinitionKey); + for (Map.Entry> entry : groupByKey.entrySet()) { + ActHistoryInfoVo historyInfoVo = new ActHistoryInfoVo(); + BeanUtils.copyProperties(entry.getValue().get(0), historyInfoVo); + actHistoryInfoVoList.stream().filter(e -> e.getTaskDefinitionKey().equals(entry.getKey()) && e.getEndTime() == null).findFirst() + .ifPresent(e -> { + historyInfoVo.setStatus("待处理"); + historyInfoVo.setStartTime(e.getStartTime()); + historyInfoVo.setEndTime(null); + historyInfoVo.setRunDuration(null); + }); + historyInfoVoList.add(historyInfoVo); + } + return historyInfoVoList; + } + + /** + * 获取审批记录 + * + * @param processInstanceId 流程实例id + */ + @Override + public Map getHistoryRecord(String processInstanceId) { + Map map = new HashMap<>(); + // 查询任务办理记录 + List list = QueryUtils.hisTaskInstanceQuery(processInstanceId).orderByHistoricTaskInstanceEndTime().desc().list(); + list = StreamUtils.sorted(list, Comparator.comparing(HistoricTaskInstance::getEndTime, Comparator.nullsFirst(Date::compareTo)).reversed()); + List actHistoryInfoVoList = new ArrayList<>(); + List processInstanceComments = taskService.getProcessInstanceComments(processInstanceId); + //附件 + List attachmentList = taskService.getProcessInstanceAttachments(processInstanceId); + for (HistoricTaskInstance historicTaskInstance : list) { + ActHistoryInfoVo actHistoryInfoVo = new ActHistoryInfoVo(); + BeanUtils.copyProperties(historicTaskInstance, actHistoryInfoVo); + if (actHistoryInfoVo.getEndTime() == null) { + actHistoryInfoVo.setStatus(TaskStatusEnum.WAITING.getStatus()); + actHistoryInfoVo.setStatusName(TaskStatusEnum.WAITING.getDesc()); + } + if (CollUtil.isNotEmpty(processInstanceComments)) { + processInstanceComments.stream().filter(e -> e.getTaskId().equals(historicTaskInstance.getId())).findFirst().ifPresent(e -> { + actHistoryInfoVo.setComment(e.getFullMessage()); + actHistoryInfoVo.setStatus(e.getType()); + actHistoryInfoVo.setStatusName(TaskStatusEnum.findByStatus(e.getType())); + }); + } + if (ObjectUtil.isNotEmpty(historicTaskInstance.getDurationInMillis())) { + actHistoryInfoVo.setRunDuration(getDuration(historicTaskInstance.getDurationInMillis())); + } + try { + actHistoryInfoVo.setAssignee(StringUtils.isNotBlank(historicTaskInstance.getAssignee()) ? Long.valueOf(historicTaskInstance.getAssignee()) : null); + } catch (NumberFormatException ignored) { + log.warn("当前任务【{}】,办理人转换人员ID【{}】异常!", historicTaskInstance.getName(), historicTaskInstance.getAssignee()); + } + //附件 + if (CollUtil.isNotEmpty(attachmentList)) { + List attachments = attachmentList.stream().filter(e -> e.getTaskId().equals(historicTaskInstance.getId())).collect(Collectors.toList()); + if (CollUtil.isNotEmpty(attachments)) { + actHistoryInfoVo.setAttachmentList(attachments); + } + } + actHistoryInfoVoList.add(actHistoryInfoVo); + } + List collect = new ArrayList<>(); + // 待办理 + List waitingTask = StreamUtils.filter(actHistoryInfoVoList, e -> e.getEndTime() == null); + // 已办理 + List finishTask = StreamUtils.filter(actHistoryInfoVoList, e -> e.getEndTime() != null); + collect.addAll(waitingTask); + collect.addAll(finishTask); + // 审批记录 + map.put("historyRecordList", collect); + List nodeInfoList = new ArrayList<>(); + Map> groupByKey = StreamUtils.groupByKey(actHistoryInfoVoList, ActHistoryInfoVo::getTaskDefinitionKey); + for (Map.Entry> entry : groupByKey.entrySet()) { + ActHistoryInfoVo actHistoryInfoVo = BeanUtil.toBean(entry.getValue().get(0), ActHistoryInfoVo.class); + String nickName = entry.getValue().stream().filter(e -> StringUtils.isNotBlank(e.getNickName()) && e.getEndTime() == null).map(ActHistoryInfoVo::getNickName).toList().stream().distinct().collect(Collectors.joining(StringUtils.SEPARATOR)); + if (StringUtils.isNotBlank(nickName)) { + actHistoryInfoVo.setNickName(nickName); + } + actHistoryInfoVoList.stream().filter(e -> e.getTaskDefinitionKey().equals(entry.getKey()) && e.getEndTime() != null).findFirst() + .ifPresent(e -> { + actHistoryInfoVo.setStatus("已处理"); + actHistoryInfoVo.setStartTime(e.getStartTime()); + }); + actHistoryInfoVoList.stream().filter(e -> e.getTaskDefinitionKey().equals(entry.getKey()) && e.getEndTime() == null).findFirst() + .ifPresent(e -> { + actHistoryInfoVo.setStatus("待处理"); + actHistoryInfoVo.setStartTime(e.getStartTime()); + actHistoryInfoVo.setEndTime(null); + actHistoryInfoVo.setRunDuration(null); + }); + nodeInfoList.add(actHistoryInfoVo); + } + // 节点信息 + map.put("nodeListInfo", nodeInfoList); + BpmnModel bpmnModel = repositoryService.getBpmnModel(list.get(0).getProcessDefinitionId()); + List graphicInfoVos = new ArrayList<>(); + Collection flowElements = bpmnModel.getMainProcess().getFlowElements(); + //节点图形信息 + buildGraphicInfo(flowElements, graphicInfoVos, bpmnModel); + map.put("graphicInfoVos", graphicInfoVos); + return map; + } + + /** + * 构建节点图形信息 + * + * @param flowElements 节点 + */ + private static void buildGraphicInfo(Collection flowElements, List graphicInfoVos, BpmnModel bpmnModel) { + for (FlowElement flowElement : flowElements) { + if (flowElement instanceof SubProcess) { + Collection subFlowElements = ((SubProcess) flowElement).getFlowElements(); + buildGraphicInfo(subFlowElements, graphicInfoVos, bpmnModel); + } else { + if (flowElement instanceof UserTask) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowElement.getId()); + GraphicInfoVo graphicInfoVo = BeanUtil.toBean(graphicInfo, GraphicInfoVo.class); + graphicInfoVo.setNodeId(flowElement.getId()); + graphicInfoVo.setNodeName(flowElement.getName()); + graphicInfoVos.add(graphicInfoVo); + } + } + } + } + + /** + * 任务完成时间处理 + * + * @param time 时间 + */ + private String getDuration(long time) { + + long day = time / (24 * 60 * 60 * 1000); + long hour = (time / (60 * 60 * 1000) - day * 24); + long minute = ((time / (60 * 1000)) - day * 24 * 60 - hour * 60); + long second = (time / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60); + + if (day > 0) { + return day + "天" + hour + "小时" + minute + "分钟"; + } + if (hour > 0) { + return hour + "小时" + minute + "分钟"; + } + if (minute > 0) { + return minute + "分钟"; + } + if (second > 0) { + return second + "秒"; + } else { + return 0 + "秒"; + } + } + + /** + * 作废流程实例,不会删除历史记录(删除运行中的实例) + * + * @param processInvalidBo 参数 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean deleteRunInstance(ProcessInvalidBo processInvalidBo) { + try { + List list = QueryUtils.taskQuery(processInvalidBo.getProcessInstanceId()).list(); + List subTasks = StreamUtils.filter(list, e -> StringUtils.isNotBlank(e.getParentTaskId())); + if (CollUtil.isNotEmpty(subTasks)) { + subTasks.forEach(e -> taskService.deleteTask(e.getId())); + } + String deleteReason = LoginHelper.getLoginUser().getNickname() + "作废了当前申请!"; + if (StringUtils.isNotBlank(processInvalidBo.getDeleteReason())) { + deleteReason = LoginHelper.getLoginUser().getNickname() + "作废理由:" + processInvalidBo.getDeleteReason(); + } + for (Task task : StreamUtils.filter(list, e -> StringUtils.isBlank(e.getParentTaskId()))) { + taskService.addComment(task.getId(), task.getProcessInstanceId(), TaskStatusEnum.INVALID.getStatus(), deleteReason); + } + HistoricProcessInstance historicProcessInstance = QueryUtils.hisInstanceQuery(processInvalidBo.getProcessInstanceId()).singleResult(); + BusinessStatusEnum.checkInvalidStatus(historicProcessInstance.getBusinessStatus()); + runtimeService.updateBusinessStatus(processInvalidBo.getProcessInstanceId(), BusinessStatusEnum.INVALID.getStatus()); + runtimeService.deleteProcessInstance(processInvalidBo.getProcessInstanceId(), deleteReason); + FlowProcessEventHandler processHandler = flowEventStrategy.getProcessHandler(historicProcessInstance.getProcessDefinitionKey()); + if (processHandler != null) { + processHandler.handleProcess(historicProcessInstance.getBusinessKey(), BusinessStatusEnum.INVALID.getStatus(), false); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + throw new ServiceException(e.getMessage()); + } + } + + /** + * 运行中的实例 删除程实例,删除历史记录,删除业务与流程关联信息 + * + * @param processInstanceIds 流程实例id + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean deleteRunAndHisInstance(List processInstanceIds) { + try { + // 1.删除运行中流程实例 + List list = QueryUtils.taskQuery(processInstanceIds).list(); + List subTasks = StreamUtils.filter(list, e -> StringUtils.isNotBlank(e.getParentTaskId())); + if (CollUtil.isNotEmpty(subTasks)) { + subTasks.forEach(e -> taskService.deleteTask(e.getId())); + } + runtimeService.bulkDeleteProcessInstances(processInstanceIds, LoginHelper.getUserId() + "删除了当前流程申请"); + // 2.删除历史记录 + List historicProcessInstanceList = QueryUtils.hisInstanceQuery(new HashSet<>(processInstanceIds)).list(); + if (ObjectUtil.isNotEmpty(historicProcessInstanceList)) { + historyService.bulkDeleteHistoricProcessInstances(processInstanceIds); + } + iWfTaskBackNodeService.deleteByInstanceIds(processInstanceIds); + return true; + } catch (Exception e) { + e.printStackTrace(); + throw new ServiceException(e.getMessage()); + } + } + + /** + * 按照业务id删除 运行中的实例 删除程实例,删除历史记录,删除业务与流程关联信息 + * + * @param businessKeys 业务id + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean deleteRunAndHisInstanceByBusinessKeys(List businessKeys) { + try { + // 1.删除运行中流程实例 + List actHiProcinsts = actHiProcinstService.selectByBusinessKeyIn(businessKeys); + if (CollUtil.isEmpty(actHiProcinsts)) { + log.warn("当前业务ID:{}查询到流程实例为空!", businessKeys); + return false; + } + List processInstanceIds = StreamUtils.toList(actHiProcinsts, ActHiProcinst::getId); + List list = QueryUtils.taskQuery(processInstanceIds).list(); + List subTasks = StreamUtils.filter(list, e -> StringUtils.isNotBlank(e.getParentTaskId())); + if (CollUtil.isNotEmpty(subTasks)) { + subTasks.forEach(e -> taskService.deleteTask(e.getId())); + } + runtimeService.bulkDeleteProcessInstances(processInstanceIds, LoginHelper.getUserId() + "删除了当前流程申请"); + // 2.删除历史记录 + List historicProcessInstanceList = QueryUtils.hisInstanceQuery(new HashSet<>(processInstanceIds)).list(); + if (ObjectUtil.isNotEmpty(historicProcessInstanceList)) { + historyService.bulkDeleteHistoricProcessInstances(processInstanceIds); + } + iWfTaskBackNodeService.deleteByInstanceIds(processInstanceIds); + return true; + } catch (Exception e) { + e.printStackTrace(); + throw new ServiceException(e.getMessage()); + } + } + + /** + * 已完成的实例 删除程实例,删除历史记录,删除业务与流程关联信息 + * + * @param processInstanceIds 流程实例id + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean deleteFinishAndHisInstance(List processInstanceIds) { + try { + historyService.bulkDeleteHistoricProcessInstances(processInstanceIds); + iWfTaskBackNodeService.deleteByInstanceIds(processInstanceIds); + return true; + } catch (Exception e) { + e.printStackTrace(); + throw new ServiceException(e.getMessage()); + } + } + + /** + * 撤销流程申请 + * + * @param processInstanceId 流程实例id + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean cancelProcessApply(String processInstanceId) { + try { + ProcessInstance processInstance = QueryUtils.instanceQuery(processInstanceId) + .startedBy(String.valueOf(LoginHelper.getUserId())).singleResult(); + if (ObjectUtil.isNull(processInstance)) { + throw new ServiceException("您不是流程发起人,撤销失败!"); + } + if (processInstance.isSuspended()) { + throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED); + } + BusinessStatusEnum.checkCancelStatus(processInstance.getBusinessStatus()); + List taskList = QueryUtils.taskQuery(processInstanceId).list(); + for (Task task : taskList) { + taskService.setAssignee(task.getId(), null); + taskService.addComment(task.getId(), processInstanceId, TaskStatusEnum.CANCEL.getStatus(), LoginHelper.getLoginUser().getNickname() + ":撤销申请"); + } + HistoricTaskInstance historicTaskInstance = QueryUtils.hisTaskInstanceQuery().finished().orderByHistoricTaskInstanceEndTime().asc().list().get(0); + List nodeIds = StreamUtils.toList(taskList, Task::getTaskDefinitionKey); + runtimeService.createChangeActivityStateBuilder() + .processInstanceId(processInstanceId) + .moveActivityIdsToSingleActivityId(nodeIds, historicTaskInstance.getTaskDefinitionKey()).changeState(); + Task task = QueryUtils.taskQuery(processInstanceId).list().get(0); + taskService.setAssignee(task.getId(), historicTaskInstance.getAssignee()); + //获取并行网关执行后保留的执行实例数据 + ExecutionChildByExecutionIdCmd childByExecutionIdCmd = new ExecutionChildByExecutionIdCmd(task.getExecutionId()); + List executionEntities = managementService.executeCommand(childByExecutionIdCmd); + //删除流程实例垃圾数据 + for (ExecutionEntity executionEntity : executionEntities) { + DeleteExecutionCmd deleteExecutionCmd = new DeleteExecutionCmd(executionEntity.getId()); + managementService.executeCommand(deleteExecutionCmd); + } + runtimeService.updateBusinessStatus(processInstanceId, BusinessStatusEnum.CANCEL.getStatus()); + FlowProcessEventHandler processHandler = flowEventStrategy.getProcessHandler(processInstance.getProcessDefinitionKey()); + if (processHandler != null) { + processHandler.handleProcess(processInstance.getBusinessKey(), BusinessStatusEnum.CANCEL.getStatus(), false); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + throw new ServiceException("撤销失败:" + e.getMessage()); + } + } + + /** + * 分页查询当前登录人单据 + * + * @param bo 参数 + */ + @Override + public TableDataInfo getPageByCurrent(ProcessInstanceBo bo, PageQuery pageQuery) { + List list = new ArrayList<>(); + HistoricProcessInstanceQuery query = QueryUtils.hisInstanceQuery(); + query.startedBy(String.valueOf(LoginHelper.getUserId())); + if (StringUtils.isNotBlank(bo.getName())) { + query.processInstanceNameLikeIgnoreCase("%" + bo.getName() + "%"); + } + if (StringUtils.isNotBlank(bo.getKey())) { + query.processDefinitionKey(bo.getKey()); + } + if (StringUtils.isNotBlank(bo.getBusinessKey())) { + query.processInstanceBusinessKey(bo.getBusinessKey()); + } + if (StringUtils.isNotBlank(bo.getCategoryCode())) { + query.processDefinitionCategory(bo.getCategoryCode()); + } + query.orderByProcessInstanceStartTime().desc(); + List historicProcessInstanceList = query.listPage(pageQuery.getFirstNum(), pageQuery.getPageSize()); + List taskVoList = new ArrayList<>(); + if (CollUtil.isNotEmpty(historicProcessInstanceList)) { + List processInstanceIds = StreamUtils.toList(historicProcessInstanceList, HistoricProcessInstance::getId); + List taskList = QueryUtils.taskQuery(processInstanceIds).list(); + for (Task task : taskList) { + taskVoList.add(BeanUtil.toBean(task, TaskVo.class)); + } + } + for (HistoricProcessInstance processInstance : historicProcessInstanceList) { + ProcessInstanceVo processInstanceVo = BeanUtil.toBean(processInstance, ProcessInstanceVo.class); + processInstanceVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(processInstance.getBusinessStatus())); + if (CollUtil.isNotEmpty(taskVoList)) { + List collect = StreamUtils.filter(taskVoList, e -> e.getProcessInstanceId().equals(processInstance.getId())); + processInstanceVo.setTaskVoList(CollUtil.isNotEmpty(collect) ? collect : Collections.emptyList()); + } + list.add(processInstanceVo); + } + if (CollUtil.isNotEmpty(list)) { + List processDefinitionIds = StreamUtils.toList(list, ProcessInstanceVo::getProcessDefinitionId); + List wfNodeConfigVoList = iWfNodeConfigService.selectByDefIds(processDefinitionIds); + for (ProcessInstanceVo processInstanceVo : list) { + if (CollUtil.isNotEmpty(wfNodeConfigVoList)) { + wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(processInstanceVo.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(processInstanceVo::setWfNodeConfigVo); + } + } + } + long count = query.count(); + TableDataInfo build = TableDataInfo.build(); + build.setRows(list); + build.setTotal(count); + return build; + } + + /** + * 任务催办(给当前任务办理人发送站内信,邮件,短信等) + * + * @param taskUrgingBo 任务催办 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean taskUrging(TaskUrgingBo taskUrgingBo) { + try { + ProcessInstance processInstance = QueryUtils.instanceQuery(taskUrgingBo.getProcessInstanceId()).singleResult(); + if (processInstance == null) { + throw new ServiceException("任务已结束!"); + } + String message = taskUrgingBo.getMessage(); + if (StringUtils.isBlank(message)) { + message = "您的【" + processInstance.getName() + "】单据还未审批,请您及时处理。"; + } + List list = QueryUtils.taskQuery(taskUrgingBo.getProcessInstanceId()).list(); + WorkflowUtils.sendMessage(list, processInstance.getName(), taskUrgingBo.getMessageType(), message); + } catch (ServiceException e) { + throw new ServiceException(e.getMessage()); + } + return true; + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java new file mode 100644 index 000000000..08d99d689 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java @@ -0,0 +1,781 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.dto.RoleDTO; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.workflow.common.constant.FlowConstant; +import org.dromara.workflow.common.enums.BusinessStatusEnum; +import org.dromara.workflow.common.enums.TaskStatusEnum; +import org.dromara.workflow.domain.ActHiTaskinst; +import org.dromara.workflow.domain.WfTaskBackNode; +import org.dromara.workflow.domain.bo.*; +import org.dromara.workflow.domain.vo.*; +import org.dromara.workflow.flowable.cmd.*; +import org.dromara.workflow.flowable.strategy.FlowEventStrategy; +import org.dromara.workflow.flowable.strategy.FlowProcessEventHandler; +import org.dromara.workflow.flowable.strategy.FlowTaskEventHandler; +import org.dromara.workflow.mapper.ActHiTaskinstMapper; +import org.dromara.workflow.mapper.ActTaskMapper; +import org.dromara.workflow.service.IActTaskService; +import org.dromara.workflow.service.IWfDefinitionConfigService; +import org.dromara.workflow.service.IWfNodeConfigService; +import org.dromara.workflow.service.IWfTaskBackNodeService; +import org.dromara.workflow.utils.ModelUtils; +import org.dromara.workflow.utils.QueryUtils; +import org.dromara.workflow.utils.WorkflowUtils; +import org.flowable.common.engine.api.FlowableObjectNotFoundException; +import org.flowable.common.engine.impl.identity.Authentication; +import org.flowable.engine.*; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.history.HistoricProcessInstanceQuery; +import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior; +import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior; +import org.flowable.engine.impl.persistence.entity.ExecutionEntity; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.identitylink.api.history.HistoricIdentityLink; +import org.flowable.task.api.Task; +import org.flowable.task.api.TaskQuery; +import org.flowable.task.api.history.HistoricTaskInstance; +import org.flowable.task.service.impl.persistence.entity.TaskEntity; +import org.flowable.variable.api.persistence.entity.VariableInstance; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +import static org.dromara.workflow.common.constant.FlowConstant.*; + +/** + * 任务 服务层实现 + * + * @author may + */ +@RequiredArgsConstructor +@Service +public class ActTaskServiceImpl implements IActTaskService { + + private final RuntimeService runtimeService; + private final TaskService taskService; + private final HistoryService historyService; + private final IdentityService identityService; + private final ManagementService managementService; + private final FlowEventStrategy flowEventStrategy; + private final ActTaskMapper actTaskMapper; + private final IWfTaskBackNodeService iWfTaskBackNodeService; + private final ActHiTaskinstMapper actHiTaskinstMapper; + private final IWfNodeConfigService iWfNodeConfigService; + private final IWfDefinitionConfigService iWfDefinitionConfigService; + + /** + * 启动任务 + * + * @param startProcessBo 启动流程参数 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Map startWorkFlow(StartProcessBo startProcessBo) { + Map map = new HashMap<>(); + if (StringUtils.isBlank(startProcessBo.getBusinessKey())) { + throw new ServiceException("启动工作流时必须包含业务ID"); + } + // 判断当前业务是否启动过流程 + HistoricProcessInstanceQuery query = QueryUtils.hisInstanceQuery(); + HistoricProcessInstance historicProcessInstance = query.processInstanceBusinessKey(startProcessBo.getBusinessKey()).singleResult(); + if (ObjectUtil.isNotEmpty(historicProcessInstance)) { + BusinessStatusEnum.checkStartStatus(historicProcessInstance.getBusinessStatus()); + } + List taskResult = QueryUtils.taskQuery().processInstanceBusinessKey(startProcessBo.getBusinessKey()).list(); + if (CollUtil.isNotEmpty(taskResult)) { + if (CollUtil.isNotEmpty(startProcessBo.getVariables())) { + taskService.setVariables(taskResult.get(0).getId(), startProcessBo.getVariables()); + } + map.put(PROCESS_INSTANCE_ID, taskResult.get(0).getProcessInstanceId()); + map.put("taskId", taskResult.get(0).getId()); + return map; + } + WfDefinitionConfigVo wfDefinitionConfigVo = iWfDefinitionConfigService.getByTableNameLastVersion(startProcessBo.getTableName()); + if (wfDefinitionConfigVo == null) { + throw new ServiceException("请到流程定义绑定业务表名与流程KEY!"); + } + // 设置启动人 + identityService.setAuthenticatedUserId(String.valueOf(LoginHelper.getUserId())); + Authentication.setAuthenticatedUserId(String.valueOf(LoginHelper.getUserId())); + // 启动流程实例(提交申请) + Map variables = startProcessBo.getVariables(); + // 启动跳过表达式 + variables.put(FLOWABLE_SKIP_EXPRESSION_ENABLED, true); + // 流程发起人 + variables.put(INITIATOR, (String.valueOf(LoginHelper.getUserId()))); + ProcessInstance pi; + try { + if (TenantHelper.isEnable()) { + pi = runtimeService.startProcessInstanceByKeyAndTenantId(wfDefinitionConfigVo.getProcessKey(), startProcessBo.getBusinessKey(), variables, TenantHelper.getTenantId()); + } else { + pi = runtimeService.startProcessInstanceByKey(wfDefinitionConfigVo.getProcessKey(), startProcessBo.getBusinessKey(), variables); + } + } catch (FlowableObjectNotFoundException e) { + throw new ServiceException("找不到当前【" + wfDefinitionConfigVo.getProcessKey() + "】流程定义!"); + } + // 将流程定义名称 作为 流程实例名称 + runtimeService.setProcessInstanceName(pi.getProcessInstanceId(), pi.getProcessDefinitionName()); + // 申请人执行流程 + List taskList = QueryUtils.taskQuery(pi.getId()).list(); + if (taskList.size() > 1) { + throw new ServiceException("请检查流程第一个环节是否为申请人!"); + } + + runtimeService.updateBusinessStatus(pi.getProcessInstanceId(), BusinessStatusEnum.DRAFT.getStatus()); + taskService.setAssignee(taskList.get(0).getId(), LoginHelper.getUserId().toString()); + taskService.setVariable(taskList.get(0).getId(), PROCESS_INSTANCE_ID, pi.getProcessInstanceId()); + taskService.setVariable(taskList.get(0).getId(), BUSINESS_KEY, pi.getBusinessKey()); + map.put("processInstanceId", pi.getProcessInstanceId()); + map.put("taskId", taskList.get(0).getId()); + return map; + } + + /** + * 办理任务 + * + * @param completeTaskBo 办理任务参数 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean completeTask(CompleteTaskBo completeTaskBo) { + try { + List roles = LoginHelper.getLoginUser().getRoles(); + String userId = String.valueOf(LoginHelper.getUserId()); + TaskQuery taskQuery = QueryUtils.taskQuery(); + taskQuery.taskId(completeTaskBo.getTaskId()).taskCandidateOrAssigned(userId); + if (CollUtil.isNotEmpty(roles)) { + List groupIds = StreamUtils.toList(roles, e -> String.valueOf(e.getRoleId())); + taskQuery.taskCandidateGroupIn(groupIds); + } + Task task = taskQuery.singleResult(); + if (task == null) { + throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL); + } + if (task.isSuspended()) { + throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED); + } + ProcessInstance processInstance = QueryUtils.instanceQuery(task.getProcessInstanceId()).singleResult(); + //办理委托任务 + if (ObjectUtil.isNotEmpty(task.getDelegationState()) && FlowConstant.PENDING.equals(task.getDelegationState().name())) { + taskService.resolveTask(completeTaskBo.getTaskId()); + TaskEntity newTask = WorkflowUtils.createNewTask(task); + taskService.addComment(newTask.getId(), task.getProcessInstanceId(), TaskStatusEnum.PASS.getStatus(), StringUtils.isNotBlank(completeTaskBo.getMessage()) ? completeTaskBo.getMessage() : StrUtil.EMPTY); + taskService.complete(newTask.getId()); + return true; + } + //附件上传 + AttachmentCmd attachmentCmd = new AttachmentCmd(completeTaskBo.getFileId(), task.getId(), task.getProcessInstanceId()); + managementService.executeCommand(attachmentCmd); + FlowProcessEventHandler processHandler = flowEventStrategy.getProcessHandler(processInstance.getProcessDefinitionKey()); + String businessStatus = WorkflowUtils.getBusinessStatus(task.getProcessInstanceId()); + if (BusinessStatusEnum.DRAFT.getStatus().equals(businessStatus) || BusinessStatusEnum.BACK.getStatus().equals(businessStatus) || BusinessStatusEnum.CANCEL.getStatus().equals(businessStatus)) { + if (processHandler != null) { + processHandler.handleProcess(processInstance.getBusinessKey(), businessStatus, true); + } + } + runtimeService.updateBusinessStatus(task.getProcessInstanceId(), BusinessStatusEnum.WAITING.getStatus()); + String key = processInstance.getProcessDefinitionKey() + "_" + task.getTaskDefinitionKey(); + FlowTaskEventHandler taskHandler = flowEventStrategy.getTaskHandler(key); + if (taskHandler != null) { + taskHandler.handleTask(task.getId(), processInstance.getBusinessKey()); + } + //办理意见 + taskService.addComment(completeTaskBo.getTaskId(), task.getProcessInstanceId(), TaskStatusEnum.PASS.getStatus(), StringUtils.isBlank(completeTaskBo.getMessage()) ? "同意" : completeTaskBo.getMessage()); + //办理任务 + taskService.setAssignee(task.getId(), userId); + if (CollUtil.isNotEmpty(completeTaskBo.getVariables())) { + taskService.complete(completeTaskBo.getTaskId(), completeTaskBo.getVariables()); + } else { + taskService.complete(completeTaskBo.getTaskId()); + } + //记录执行过的流程任务节点 + iWfTaskBackNodeService.recordExecuteNode(task); + ProcessInstance pi = QueryUtils.instanceQuery(task.getProcessInstanceId()).singleResult(); + if (pi == null) { + UpdateBusinessStatusCmd updateBusinessStatusCmd = new UpdateBusinessStatusCmd(task.getProcessInstanceId(), BusinessStatusEnum.FINISH.getStatus()); + managementService.executeCommand(updateBusinessStatusCmd); + if (processHandler != null) { + processHandler.handleProcess(processInstance.getBusinessKey(), BusinessStatusEnum.FINISH.getStatus(), false); + } + } else { + List list = QueryUtils.taskQuery(task.getProcessInstanceId()).list(); + for (Task t : list) { + if (ModelUtils.isUserTask(t.getProcessDefinitionId(), t.getTaskDefinitionKey())) { + List links = historyService.getHistoricIdentityLinksForTask(t.getId()); + if (CollUtil.isEmpty(links) && StringUtils.isBlank(t.getAssignee())) { + throw new ServiceException("下一节点【" + t.getName() + "】没有办理人!"); + } + } + } + + if (CollUtil.isNotEmpty(list) && CollUtil.isNotEmpty(completeTaskBo.getWfCopyList())) { + TaskEntity newTask = WorkflowUtils.createNewTask(task); + taskService.addComment(newTask.getId(), task.getProcessInstanceId(), TaskStatusEnum.COPY.getStatus(), LoginHelper.getLoginUser().getNickname() + "【抄送】给" + String.join(",", StreamUtils.toList(completeTaskBo.getWfCopyList(), WfCopy::getUserName))); + taskService.complete(newTask.getId()); + List taskList = QueryUtils.taskQuery(task.getProcessInstanceId()).list(); + WorkflowUtils.createCopyTask(taskList, StreamUtils.toList(completeTaskBo.getWfCopyList(), WfCopy::getUserId)); + } + sendMessage(list, processInstance.getName(), completeTaskBo.getMessageType(), null); + } + return true; + } catch (Exception e) { + throw new ServiceException(e.getMessage()); + } + } + + /** + * 发送消息 + * + * @param list 任务 + * @param name 流程名称 + * @param messageType 消息类型 + * @param message 消息内容,为空则发送默认配置的消息内容 + */ + @Async + public void sendMessage(List list, String name, List messageType, String message) { + WorkflowUtils.sendMessage(list, name, messageType, message); + } + + /** + * 查询当前用户的待办任务 + * + * @param taskBo 参数 + */ + @Override + public TableDataInfo getPageByTaskWait(TaskBo taskBo, PageQuery pageQuery) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + List roles = LoginHelper.getLoginUser().getRoles(); + List roleIds = StreamUtils.toList(roles, e -> String.valueOf(e.getRoleId())); + String userId = String.valueOf(LoginHelper.getUserId()); + queryWrapper.eq("t.business_status_", BusinessStatusEnum.WAITING.getStatus()); + queryWrapper.eq(TenantHelper.isEnable(), "t.tenant_id_", TenantHelper.getTenantId()); + queryWrapper.and(w1 -> w1.eq("t.assignee_", userId).or(w2 -> w2.isNull("t.assignee_").apply("exists ( select LINK.ID_ from ACT_RU_IDENTITYLINK LINK where LINK.TASK_ID_ = t.ID_ and LINK.TYPE_ = 'candidate' " + "and (LINK.USER_ID_ = {0} or ( LINK.GROUP_ID_ IN " + getInParam(roleIds) + " ) ))", userId))); + if (StringUtils.isNotBlank(taskBo.getName())) { + queryWrapper.like("t.name_", taskBo.getName()); + } + if (StringUtils.isNotBlank(taskBo.getProcessDefinitionName())) { + queryWrapper.like("t.processDefinitionName", taskBo.getProcessDefinitionName()); + } + if (StringUtils.isNotBlank(taskBo.getProcessDefinitionKey())) { + queryWrapper.eq("t.processDefinitionKey", taskBo.getProcessDefinitionKey()); + } + Page page = actTaskMapper.getTaskWaitByPage(pageQuery.build(), queryWrapper); + + List taskList = page.getRecords(); + if (CollUtil.isNotEmpty(taskList)) { + List processDefinitionIds = StreamUtils.toList(taskList, TaskVo::getProcessDefinitionId); + List wfNodeConfigVoList = iWfNodeConfigService.selectByDefIds(processDefinitionIds); + for (TaskVo task : taskList) { + task.setBusinessStatusName(BusinessStatusEnum.findByStatus(task.getBusinessStatus())); + task.setParticipantVo(WorkflowUtils.getCurrentTaskParticipant(task.getId())); + task.setMultiInstance(WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey()) != null); + if (CollUtil.isNotEmpty(wfNodeConfigVoList)) { + wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo); + wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && e.getNodeId().equals(task.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo); + } + } + } + return TableDataInfo.build(page); + } + + private String getInParam(List param) { + StringBuilder sb = new StringBuilder(); + sb.append("("); + for (int i = 0; i < param.size(); i++) { + sb.append("'").append(param.get(i)).append("'"); + if (i != param.size() - 1) { + sb.append(","); + } + } + sb.append(")"); + return sb.toString(); + } + + /** + * 查询当前租户所有待办任务 + * + * @param taskBo 参数 + */ + @Override + public TableDataInfo getPageByAllTaskWait(TaskBo taskBo, PageQuery pageQuery) { + TaskQuery query = QueryUtils.taskQuery(); + if (StringUtils.isNotBlank(taskBo.getName())) { + query.taskNameLike("%" + taskBo.getName() + "%"); + } + if (StringUtils.isNotBlank(taskBo.getProcessDefinitionName())) { + query.processDefinitionNameLike("%" + taskBo.getProcessDefinitionName() + "%"); + } + if (StringUtils.isNotBlank(taskBo.getProcessDefinitionKey())) { + query.processDefinitionKey(taskBo.getProcessDefinitionKey()); + } + query.orderByTaskCreateTime().desc(); + List taskList = query.listPage(pageQuery.getFirstNum(), pageQuery.getPageSize()); + List processInstanceList = null; + if (CollUtil.isNotEmpty(taskList)) { + Set processInstanceIds = StreamUtils.toSet(taskList, Task::getProcessInstanceId); + processInstanceList = QueryUtils.instanceQuery(processInstanceIds).list(); + } + List list = new ArrayList<>(); + if (CollUtil.isNotEmpty(taskList)) { + List processDefinitionIds = StreamUtils.toList(taskList, Task::getProcessDefinitionId); + List wfNodeConfigVoList = iWfNodeConfigService.selectByDefIds(processDefinitionIds); + for (Task task : taskList) { + TaskVo taskVo = BeanUtil.toBean(task, TaskVo.class); + if (CollUtil.isNotEmpty(processInstanceList)) { + processInstanceList.stream().filter(e -> e.getId().equals(task.getProcessInstanceId())).findFirst().ifPresent(e -> { + taskVo.setBusinessStatus(e.getBusinessStatus()); + taskVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(taskVo.getBusinessStatus())); + taskVo.setProcessDefinitionKey(e.getProcessDefinitionKey()); + taskVo.setProcessDefinitionName(e.getProcessDefinitionName()); + taskVo.setProcessDefinitionVersion(e.getProcessDefinitionVersion()); + taskVo.setBusinessKey(e.getBusinessKey()); + }); + } + taskVo.setAssignee(StringUtils.isNotBlank(task.getAssignee()) ? Long.valueOf(task.getAssignee()) : null); + taskVo.setParticipantVo(WorkflowUtils.getCurrentTaskParticipant(task.getId())); + taskVo.setMultiInstance(WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey()) != null); + if (CollUtil.isNotEmpty(wfNodeConfigVoList)) { + wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(taskVo::setWfNodeConfigVo); + wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && e.getNodeId().equals(task.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(taskVo::setWfNodeConfigVo); + } + list.add(taskVo); + } + } + long count = query.count(); + TableDataInfo build = TableDataInfo.build(); + build.setRows(list); + build.setTotal(count); + return build; + } + + /** + * 查询当前用户的已办任务 + * + * @param taskBo 参数 + */ + @Override + public TableDataInfo getPageByTaskFinish(TaskBo taskBo, PageQuery pageQuery) { + String userId = String.valueOf(LoginHelper.getUserId()); + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.like(StringUtils.isNotBlank(taskBo.getName()), "t.name_", taskBo.getName()); + queryWrapper.like(StringUtils.isNotBlank(taskBo.getProcessDefinitionName()), "t.processDefinitionName", taskBo.getProcessDefinitionName()); + queryWrapper.eq(StringUtils.isNotBlank(taskBo.getProcessDefinitionKey()), "t.processDefinitionKey", taskBo.getProcessDefinitionKey()); + queryWrapper.eq("t.assignee_", userId); + Page page = actTaskMapper.getTaskFinishByPage(pageQuery.build(), queryWrapper); + + List taskList = page.getRecords(); + if (CollUtil.isNotEmpty(taskList)) { + List processDefinitionIds = StreamUtils.toList(taskList, TaskVo::getProcessDefinitionId); + List wfNodeConfigVoList = iWfNodeConfigService.selectByDefIds(processDefinitionIds); + for (TaskVo task : taskList) { + task.setBusinessStatusName(BusinessStatusEnum.findByStatus(task.getBusinessStatus())); + if (CollUtil.isNotEmpty(wfNodeConfigVoList)) { + wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo); + wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && e.getNodeId().equals(task.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo); + } + } + } + return TableDataInfo.build(page); + } + + /** + * 查询当前用户的抄送 + * + * @param taskBo 参数 + */ + @Override + public TableDataInfo getPageByTaskCopy(TaskBo taskBo, PageQuery pageQuery) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + String userId = String.valueOf(LoginHelper.getUserId()); + if (StringUtils.isNotBlank(taskBo.getName())) { + queryWrapper.like("t.name_", taskBo.getName()); + } + if (StringUtils.isNotBlank(taskBo.getProcessDefinitionName())) { + queryWrapper.like("t.processDefinitionName", taskBo.getProcessDefinitionName()); + } + if (StringUtils.isNotBlank(taskBo.getProcessDefinitionKey())) { + queryWrapper.eq("t.processDefinitionKey", taskBo.getProcessDefinitionKey()); + } + queryWrapper.eq("t.assignee_", userId); + Page page = actTaskMapper.getTaskCopyByPage(pageQuery.build(), queryWrapper); + + List taskList = page.getRecords(); + if (CollUtil.isNotEmpty(taskList)) { + List processDefinitionIds = StreamUtils.toList(taskList, TaskVo::getProcessDefinitionId); + List wfNodeConfigVoList = iWfNodeConfigService.selectByDefIds(processDefinitionIds); + for (TaskVo task : taskList) { + task.setBusinessStatusName(BusinessStatusEnum.findByStatus(task.getBusinessStatus())); + if (CollUtil.isNotEmpty(wfNodeConfigVoList)) { + wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo); + wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && e.getNodeId().equals(task.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo); + } + } + } + return TableDataInfo.build(page); + } + + /** + * 查询当前租户所有已办任务 + * + * @param taskBo 参数 + */ + @Override + public TableDataInfo getPageByAllTaskFinish(TaskBo taskBo, PageQuery pageQuery) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.like(StringUtils.isNotBlank(taskBo.getName()), "t.name_", taskBo.getName()); + queryWrapper.like(StringUtils.isNotBlank(taskBo.getProcessDefinitionName()), "t.processDefinitionName", taskBo.getProcessDefinitionName()); + queryWrapper.eq(StringUtils.isNotBlank(taskBo.getProcessDefinitionKey()), "t.processDefinitionKey", taskBo.getProcessDefinitionKey()); + Page page = actTaskMapper.getTaskFinishByPage(pageQuery.build(), queryWrapper); + + List taskList = page.getRecords(); + if (CollUtil.isNotEmpty(taskList)) { + List processDefinitionIds = StreamUtils.toList(taskList, TaskVo::getProcessDefinitionId); + List wfNodeConfigVoList = iWfNodeConfigService.selectByDefIds(processDefinitionIds); + for (TaskVo task : taskList) { + task.setBusinessStatusName(BusinessStatusEnum.findByStatus(task.getBusinessStatus())); + if (CollUtil.isNotEmpty(wfNodeConfigVoList)) { + wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo); + wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && e.getNodeId().equals(task.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo); + } + } + } + return TableDataInfo.build(page); + } + + /** + * 委派任务 + * + * @param delegateBo 参数 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean delegateTask(DelegateBo delegateBo) { + TaskQuery query = QueryUtils.taskQuery(); + TaskEntity task = (TaskEntity) query.taskId(delegateBo.getTaskId()).taskCandidateOrAssigned(String.valueOf(LoginHelper.getUserId())).singleResult(); + if (ObjectUtil.isEmpty(task)) { + throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL); + } + if (task.isSuspended()) { + throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED); + } + try { + TaskEntity newTask = WorkflowUtils.createNewTask(task); + taskService.addComment(newTask.getId(), task.getProcessInstanceId(), TaskStatusEnum.PENDING.getStatus(), "【" + LoginHelper.getLoginUser().getNickname() + "】委派给【" + delegateBo.getNickName() + "】"); + //委托任务 + taskService.delegateTask(delegateBo.getTaskId(), delegateBo.getUserId()); + //办理生成的任务记录 + taskService.complete(newTask.getId()); + return true; + } catch (Exception e) { + e.printStackTrace(); + throw new ServiceException(e.getMessage()); + } + } + + /** + * 终止任务 + * + * @param terminationBo 参数 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean terminationTask(TerminationBo terminationBo) { + TaskQuery query = QueryUtils.taskQuery(); + Task task = query.taskId(terminationBo.getTaskId()).singleResult(); + + if (ObjectUtil.isEmpty(task)) { + throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL); + } + if (task.isSuspended()) { + throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED); + } + HistoricProcessInstance historicProcessInstance = QueryUtils.hisInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult(); + BusinessStatusEnum.checkInvalidStatus(historicProcessInstance.getBusinessStatus()); + try { + if (StringUtils.isBlank(terminationBo.getComment())) { + terminationBo.setComment(LoginHelper.getLoginUser().getNickname() + "终止了申请"); + } else { + terminationBo.setComment(LoginHelper.getLoginUser().getNickname() + "终止了申请:" + terminationBo.getComment()); + } + taskService.addComment(task.getId(), task.getProcessInstanceId(), TaskStatusEnum.TERMINATION.getStatus(), terminationBo.getComment()); + List list = QueryUtils.taskQuery(task.getProcessInstanceId()).list(); + if (CollectionUtil.isNotEmpty(list)) { + List subTasks = StreamUtils.filter(list, e -> StringUtils.isNotBlank(e.getParentTaskId())); + if (CollectionUtil.isNotEmpty(subTasks)) { + subTasks.forEach(e -> taskService.deleteTask(e.getId())); + } + runtimeService.updateBusinessStatus(task.getProcessInstanceId(), BusinessStatusEnum.TERMINATION.getStatus()); + runtimeService.deleteProcessInstance(task.getProcessInstanceId(), StrUtil.EMPTY); + } + FlowProcessEventHandler processHandler = flowEventStrategy.getProcessHandler(historicProcessInstance.getProcessDefinitionKey()); + if (processHandler != null) { + processHandler.handleProcess(historicProcessInstance.getBusinessKey(), BusinessStatusEnum.TERMINATION.getStatus(), false); + } + return true; + } catch (Exception e) { + throw new ServiceException(e.getMessage()); + } + } + + /** + * 转办任务 + * + * @param transmitBo 参数 + */ + @Override + public boolean transferTask(TransmitBo transmitBo) { + Task task = QueryUtils.taskQuery().taskId(transmitBo.getTaskId()).taskCandidateOrAssigned(String.valueOf(LoginHelper.getUserId())).singleResult(); + if (ObjectUtil.isEmpty(task)) { + throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL); + } + if (task.isSuspended()) { + throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED); + } + try { + TaskEntity newTask = WorkflowUtils.createNewTask(task); + taskService.addComment(newTask.getId(), task.getProcessInstanceId(), TaskStatusEnum.TRANSFER.getStatus(), StringUtils.isNotBlank(transmitBo.getComment()) ? transmitBo.getComment() : LoginHelper.getUsername() + "转办了任务"); + taskService.complete(newTask.getId()); + taskService.setAssignee(task.getId(), transmitBo.getUserId()); + return true; + } catch (Exception e) { + e.printStackTrace(); + throw new ServiceException(e.getMessage()); + } + } + + /** + * 会签任务加签 + * + * @param addMultiBo 参数 + */ + @Override + public boolean addMultiInstanceExecution(AddMultiBo addMultiBo) { + TaskQuery taskQuery = QueryUtils.taskQuery(); + taskQuery.taskId(addMultiBo.getTaskId()); + if (!LoginHelper.isSuperAdmin() && !LoginHelper.isTenantAdmin()) { + taskQuery.taskCandidateOrAssigned(String.valueOf(LoginHelper.getUserId())); + } + Task task = taskQuery.singleResult(); + if (ObjectUtil.isEmpty(task)) { + throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL); + } + if (task.isSuspended()) { + throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED); + } + String taskDefinitionKey = task.getTaskDefinitionKey(); + String processInstanceId = task.getProcessInstanceId(); + String processDefinitionId = task.getProcessDefinitionId(); + + try { + MultiInstanceVo multiInstanceVo = WorkflowUtils.isMultiInstance(processDefinitionId, taskDefinitionKey); + if (multiInstanceVo == null) { + throw new ServiceException("当前环节不是会签节点"); + } + if (multiInstanceVo.getType() instanceof ParallelMultiInstanceBehavior) { + for (Long assignee : addMultiBo.getAssignees()) { + runtimeService.addMultiInstanceExecution(taskDefinitionKey, processInstanceId, Collections.singletonMap(multiInstanceVo.getAssignee(), assignee)); + } + } else if (multiInstanceVo.getType() instanceof SequentialMultiInstanceBehavior) { + AddSequenceMultiInstanceCmd addSequenceMultiInstanceCmd = new AddSequenceMultiInstanceCmd(task.getExecutionId(), multiInstanceVo.getAssigneeList(), addMultiBo.getAssignees()); + managementService.executeCommand(addSequenceMultiInstanceCmd); + } + List assigneeNames = addMultiBo.getAssigneeNames(); + String username = LoginHelper.getUsername(); + TaskEntity newTask = WorkflowUtils.createNewTask(task); + taskService.addComment(newTask.getId(), processInstanceId, TaskStatusEnum.SIGN.getStatus(), username + "加签【" + String.join(StringUtils.SEPARATOR, assigneeNames) + "】"); + taskService.complete(newTask.getId()); + return true; + } catch (Exception e) { + e.printStackTrace(); + throw new ServiceException(e.getMessage()); + } + } + + /** + * 会签任务减签 + * + * @param deleteMultiBo 参数 + */ + @Override + public boolean deleteMultiInstanceExecution(DeleteMultiBo deleteMultiBo) { + TaskQuery taskQuery = QueryUtils.taskQuery(); + taskQuery.taskId(deleteMultiBo.getTaskId()); + if (!LoginHelper.isSuperAdmin() && !LoginHelper.isTenantAdmin()) { + taskQuery.taskCandidateOrAssigned(String.valueOf(LoginHelper.getUserId())); + } + Task task = taskQuery.singleResult(); + if (ObjectUtil.isEmpty(task)) { + throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL); + } + if (task.isSuspended()) { + throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED); + } + String taskDefinitionKey = task.getTaskDefinitionKey(); + String processInstanceId = task.getProcessInstanceId(); + String processDefinitionId = task.getProcessDefinitionId(); + try { + MultiInstanceVo multiInstanceVo = WorkflowUtils.isMultiInstance(processDefinitionId, taskDefinitionKey); + if (multiInstanceVo == null) { + throw new ServiceException("当前环节不是会签节点"); + } + if (multiInstanceVo.getType() instanceof ParallelMultiInstanceBehavior) { + for (String executionId : deleteMultiBo.getExecutionIds()) { + runtimeService.deleteMultiInstanceExecution(executionId, false); + } + for (String taskId : deleteMultiBo.getTaskIds()) { + historyService.deleteHistoricTaskInstance(taskId); + } + } else if (multiInstanceVo.getType() instanceof SequentialMultiInstanceBehavior) { + DeleteSequenceMultiInstanceCmd deleteSequenceMultiInstanceCmd = new DeleteSequenceMultiInstanceCmd(task.getAssignee(), task.getExecutionId(), multiInstanceVo.getAssigneeList(), deleteMultiBo.getAssigneeIds()); + managementService.executeCommand(deleteSequenceMultiInstanceCmd); + } + List assigneeNames = deleteMultiBo.getAssigneeNames(); + String username = LoginHelper.getUsername(); + TaskEntity newTask = WorkflowUtils.createNewTask(task); + taskService.addComment(newTask.getId(), processInstanceId, TaskStatusEnum.SIGN_OFF.getStatus(), username + "减签【" + String.join(StringUtils.SEPARATOR, assigneeNames) + "】"); + taskService.complete(newTask.getId()); + return true; + } catch (Exception e) { + e.printStackTrace(); + throw new ServiceException(e.getMessage()); + } + } + + /** + * 驳回审批 + * + * @param backProcessBo 参数 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public String backProcess(BackProcessBo backProcessBo) { + TaskQuery query = QueryUtils.taskQuery(); + String userId = String.valueOf(LoginHelper.getUserId()); + Task task = query.taskId(backProcessBo.getTaskId()).taskCandidateOrAssigned(userId).singleResult(); + if (ObjectUtil.isEmpty(task)) { + throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL); + } + if (task.isSuspended()) { + throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED); + } + try { + String processInstanceId = task.getProcessInstanceId(); + ProcessInstance processInstance = QueryUtils.instanceQuery(task.getProcessInstanceId()).singleResult(); + //获取并行网关执行后保留的执行实例数据 + ExecutionChildByExecutionIdCmd childByExecutionIdCmd = new ExecutionChildByExecutionIdCmd(task.getExecutionId()); + List executionEntities = managementService.executeCommand(childByExecutionIdCmd); + //校验单据 + BusinessStatusEnum.checkBackStatus(processInstance.getBusinessStatus()); + //判断是否有多个任务 + List taskList = QueryUtils.taskQuery(processInstanceId).list(); + String backTaskDefinitionKey = backProcessBo.getTargetActivityId(); + taskService.addComment(task.getId(), processInstanceId, TaskStatusEnum.BACK.getStatus(), StringUtils.isNotBlank(backProcessBo.getMessage()) ? backProcessBo.getMessage() : "退回"); + if (taskList.size() > 1) { + //当前多个任务驳回到单个节点 + runtimeService.createChangeActivityStateBuilder().processInstanceId(processInstanceId).moveActivityIdsToSingleActivityId(taskList.stream().map(Task::getTaskDefinitionKey).distinct().collect(Collectors.toList()), backTaskDefinitionKey).changeState(); + ActHiTaskinst actHiTaskinst = new ActHiTaskinst(); + actHiTaskinst.setAssignee(userId); + actHiTaskinst.setId(task.getId()); + actHiTaskinstMapper.updateById(actHiTaskinst); + } else { + //当前单个节点驳回单个节点 + runtimeService.createChangeActivityStateBuilder().processInstanceId(processInstanceId).moveActivityIdTo(task.getTaskDefinitionKey(), backTaskDefinitionKey).changeState(); + } + //删除并行环节未办理记录 + MultiInstanceVo multiInstance = WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey()); + if (multiInstance == null && taskList.size() > 1) { + List tasks = StreamUtils.filter(taskList, e -> !e.getTaskDefinitionKey().equals(task.getTaskDefinitionKey())); + actHiTaskinstMapper.deleteBatchIds(StreamUtils.toList(tasks, Task::getId)); + } + + + List instanceList = QueryUtils.hisTaskInstanceQuery(processInstanceId).finished().orderByHistoricTaskInstanceEndTime().desc().list(); + List list = QueryUtils.taskQuery(processInstanceId).list(); + for (Task t : list) { + instanceList.stream().filter(e -> e.getTaskDefinitionKey().equals(t.getTaskDefinitionKey())).findFirst().ifPresent(e -> { + taskService.setAssignee(t.getId(), e.getAssignee()); + }); + } + //发送消息 + String message = "您的【" + processInstance.getName() + "】单据已经被驳回,请您注意查收。"; + sendMessage(list, processInstance.getName(), backProcessBo.getMessageType(), message); + //删除流程实例垃圾数据 + for (ExecutionEntity executionEntity : executionEntities) { + DeleteExecutionCmd deleteExecutionCmd = new DeleteExecutionCmd(executionEntity.getId()); + managementService.executeCommand(deleteExecutionCmd); + } + + WfTaskBackNode wfTaskBackNode = iWfTaskBackNodeService.getListByInstanceIdAndNodeId(task.getProcessInstanceId(), backProcessBo.getTargetActivityId()); + if (ObjectUtil.isNotNull(wfTaskBackNode) && wfTaskBackNode.getOrderNo() == 0) { + runtimeService.updateBusinessStatus(processInstanceId, BusinessStatusEnum.BACK.getStatus()); + FlowProcessEventHandler processHandler = flowEventStrategy.getProcessHandler(processInstance.getProcessDefinitionKey()); + if (processHandler != null) { + processHandler.handleProcess(processInstance.getBusinessKey(), BusinessStatusEnum.BACK.getStatus(), false); + } + } + //删除驳回后的流程节点 + iWfTaskBackNodeService.deleteBackTaskNode(processInstanceId, backProcessBo.getTargetActivityId()); + } catch (Exception e) { + throw new ServiceException(e.getMessage()); + } + return task.getProcessInstanceId(); + } + + /** + * 修改任务办理人 + * + * @param taskIds 任务id + * @param userId 办理人id + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean updateAssignee(String[] taskIds, String userId) { + try { + List list = QueryUtils.taskQuery().taskIds(Arrays.asList(taskIds)).list(); + for (Task task : list) { + taskService.setAssignee(task.getId(), userId); + } + } catch (Exception e) { + throw new ServiceException("修改失败:" + e.getMessage()); + } + return true; + } + + /** + * 查询流程变量 + * + * @param taskId 任务id + */ + @Override + public List getInstanceVariable(String taskId) { + List variableVoList = new ArrayList<>(); + Map variableInstances = taskService.getVariableInstances(taskId); + if (CollectionUtil.isNotEmpty(variableInstances)) { + for (Map.Entry entry : variableInstances.entrySet()) { + VariableVo variableVo = new VariableVo(); + variableVo.setKey(entry.getKey()); + variableVo.setValue(entry.getValue().getValue().toString()); + variableVoList.add(variableVo); + } + } + return variableVoList; + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java new file mode 100644 index 000000000..8d0086994 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java @@ -0,0 +1,121 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.workflow.domain.TestLeave; +import org.dromara.workflow.domain.bo.TestLeaveBo; +import org.dromara.workflow.domain.vo.TestLeaveVo; +import org.dromara.workflow.mapper.TestLeaveMapper; +import org.dromara.workflow.service.IActProcessInstanceService; +import org.dromara.workflow.service.ITestLeaveService; +import org.dromara.workflow.utils.WorkflowUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.List; + +/** + * 请假Service业务层处理 + * + * @author may + * @date 2023-07-21 + */ +@RequiredArgsConstructor +@Service +public class TestLeaveServiceImpl implements ITestLeaveService { + + private final TestLeaveMapper baseMapper; + private final IActProcessInstanceService iActProcessInstanceService; + + /** + * 查询请假 + */ + @Override + public TestLeaveVo queryById(Long id) { + TestLeaveVo testLeaveVo = baseMapper.selectVoById(id); + WorkflowUtils.setProcessInstanceVo(testLeaveVo, String.valueOf(id)); + return testLeaveVo; + } + + /** + * 查询请假列表 + */ + @Override + public TableDataInfo queryPageList(TestLeaveBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + TableDataInfo build = TableDataInfo.build(result); + List rows = build.getRows(); + if (CollUtil.isNotEmpty(rows)) { + List ids = StreamUtils.toList(rows, e -> String.valueOf(e.getId())); + WorkflowUtils.setProcessInstanceListVo(rows, ids, "id"); + } + return build; + } + + /** + * 查询请假列表 + */ + @Override + public List queryList(TestLeaveBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(TestLeaveBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(StringUtils.isNotBlank(bo.getLeaveType()), TestLeave::getLeaveType, bo.getLeaveType()); + lqw.ge(bo.getStartLeaveDays() != null, TestLeave::getLeaveDays, bo.getStartLeaveDays()); + lqw.le(bo.getEndLeaveDays() != null, TestLeave::getLeaveDays, bo.getEndLeaveDays()); + lqw.orderByDesc(BaseEntity::getCreateTime); + return lqw; + } + + /** + * 新增请假 + */ + @Override + public TestLeaveVo insertByBo(TestLeaveBo bo) { + TestLeave add = MapstructUtils.convert(bo, TestLeave.class); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + TestLeaveVo testLeaveVo = MapstructUtils.convert(add, TestLeaveVo.class); + WorkflowUtils.setProcessInstanceVo(testLeaveVo, String.valueOf(add.getId())); + return testLeaveVo; + } + + /** + * 修改请假 + */ + @Override + public TestLeaveVo updateByBo(TestLeaveBo bo) { + TestLeave update = MapstructUtils.convert(bo, TestLeave.class); + baseMapper.updateById(update); + TestLeaveVo testLeaveVo = MapstructUtils.convert(update, TestLeaveVo.class); + WorkflowUtils.setProcessInstanceVo(testLeaveVo, String.valueOf(update.getId())); + return testLeaveVo; + } + + /** + * 批量删除请假 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids) { + List idList = StreamUtils.toList(ids, String::valueOf); + iActProcessInstanceService.deleteRunAndHisInstanceByBusinessKeys(idList); + return baseMapper.deleteBatchIds(ids) > 0; + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfCategoryServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfCategoryServiceImpl.java new file mode 100644 index 000000000..c5cb28887 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfCategoryServiceImpl.java @@ -0,0 +1,129 @@ +package org.dromara.workflow.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.workflow.domain.WfCategory; +import org.dromara.workflow.domain.bo.WfCategoryBo; +import org.dromara.workflow.domain.vo.WfCategoryVo; +import org.dromara.workflow.mapper.WfCategoryMapper; +import org.dromara.workflow.service.IWfCategoryService; +import org.dromara.workflow.utils.QueryUtils; +import org.flowable.engine.RepositoryService; +import org.flowable.engine.repository.Deployment; +import org.flowable.engine.repository.Model; +import org.flowable.engine.repository.ProcessDefinition; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.List; + +/** + * 流程分类Service业务层处理 + * + * @author may + * @date 2023-06-28 + */ +@RequiredArgsConstructor +@Service +public class WfCategoryServiceImpl implements IWfCategoryService { + + private final WfCategoryMapper baseMapper; + + private final RepositoryService repositoryService; + + /** + * 查询流程分类 + */ + @Override + public WfCategoryVo queryById(Long id) { + return baseMapper.selectVoById(id); + } + + + /** + * 查询流程分类列表 + */ + @Override + public List queryList(WfCategoryBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(WfCategoryBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.like(StringUtils.isNotBlank(bo.getCategoryName()), WfCategory::getCategoryName, bo.getCategoryName()); + lqw.eq(StringUtils.isNotBlank(bo.getCategoryCode()), WfCategory::getCategoryCode, bo.getCategoryCode()); + return lqw; + } + + /** + * 新增流程分类 + */ + @Override + public Boolean insertByBo(WfCategoryBo bo) { + WfCategory add = MapstructUtils.convert(bo, WfCategory.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改流程分类 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean updateByBo(WfCategoryBo bo) { + WfCategory update = MapstructUtils.convert(bo, WfCategory.class); + validEntityBeforeSave(update); + WfCategoryVo wfCategoryVo = baseMapper.selectVoById(bo.getId()); + List processDefinitionList = QueryUtils.definitionQuery().processDefinitionCategory(wfCategoryVo.getCategoryCode()).list(); + for (ProcessDefinition processDefinition : processDefinitionList) { + repositoryService.setProcessDefinitionCategory(processDefinition.getId(), bo.getCategoryCode()); + } + List deploymentList = QueryUtils.deploymentQuery().deploymentCategory(wfCategoryVo.getCategoryCode()).list(); + for (Deployment deployment : deploymentList) { + repositoryService.setDeploymentCategory(deployment.getId(), bo.getCategoryCode()); + } + List modelList = QueryUtils.modelQuery().modelCategory(wfCategoryVo.getCategoryCode()).list(); + for (Model model : modelList) { + model.setCategory(bo.getCategoryCode()); + repositoryService.saveModel(model); + } + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(WfCategory entity) { + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 批量删除流程分类 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteBatchIds(ids) > 0; + } + + /** + * 按照类别编码查询 + * + * @param categoryCode 分类比吗 + */ + @Override + public WfCategory queryByCategoryCode(String categoryCode) { + return baseMapper.selectOne(new LambdaQueryWrapper().eq(WfCategory::getCategoryCode, categoryCode)); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfDefinitionConfigServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfDefinitionConfigServiceImpl.java new file mode 100644 index 000000000..947882570 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfDefinitionConfigServiceImpl.java @@ -0,0 +1,117 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.collection.CollUtil; +import org.dromara.common.core.utils.MapstructUtils; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.RequiredArgsConstructor; +import org.dromara.workflow.domain.WfDefinitionConfig; +import org.dromara.workflow.domain.bo.WfDefinitionConfigBo; +import org.dromara.workflow.domain.vo.WfDefinitionConfigVo; +import org.dromara.workflow.service.IWfDefinitionConfigService; +import org.springframework.stereotype.Service; +import org.dromara.workflow.mapper.WfDefinitionConfigMapper; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Collection; + +/** + * 流程定义配置Service业务层处理 + * + * @author may + * @date 2024-03-18 + */ +@RequiredArgsConstructor +@Service +public class WfDefinitionConfigServiceImpl implements IWfDefinitionConfigService { + + private final WfDefinitionConfigMapper baseMapper; + + /** + * 查询流程定义配置 + */ + @Override + public WfDefinitionConfigVo getByDefId(String definitionId) { + return baseMapper.selectVoOne(new LambdaQueryWrapper().eq(WfDefinitionConfig::getDefinitionId, definitionId)); + } + + /** + * 查询流程定义配置 + * + * @param tableName 表名 + * @return 结果 + */ + @Override + public WfDefinitionConfigVo getByTableNameLastVersion(String tableName) { + List wfDefinitionConfigVos = baseMapper.selectVoList( + new LambdaQueryWrapper().eq(WfDefinitionConfig::getTableName, tableName).orderByDesc(WfDefinitionConfig::getVersion)); + if (CollUtil.isNotEmpty(wfDefinitionConfigVos)) { + return wfDefinitionConfigVos.get(0); + } + return null; + } + + /** + * 查询流程定义配置 + * + * @param definitionId 流程定义id + * @param tableName 表名 + * @return 结果 + */ + @Override + public WfDefinitionConfigVo getByDefIdAndTableName(String definitionId, String tableName) { + return baseMapper.selectVoOne(new LambdaQueryWrapper() + .eq(WfDefinitionConfig::getDefinitionId, definitionId) + .eq(WfDefinitionConfig::getTableName, tableName)); + } + + /** + * 查询流程定义配置排除当前查询的流程定义 + * + * @param tableName 表名 + * @param definitionId 流程定义id + */ + @Override + public List getByTableNameNotDefId(String tableName, String definitionId) { + return baseMapper.selectVoList(new LambdaQueryWrapper() + .eq(WfDefinitionConfig::getTableName, tableName) + .ne(WfDefinitionConfig::getDefinitionId, definitionId)); + } + + /** + * 查询流程定义配置列表 + */ + @Override + public List queryList(List definitionIds) { + return baseMapper.selectVoList(new LambdaQueryWrapper().in(WfDefinitionConfig::getDefinitionId, definitionIds)); + } + + /** + * 新增流程定义配置 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean saveOrUpdate(WfDefinitionConfigBo bo) { + WfDefinitionConfig add = MapstructUtils.convert(bo, WfDefinitionConfig.class); + baseMapper.delete(new LambdaQueryWrapper().eq(WfDefinitionConfig::getTableName, bo.getTableName())); + add.setTableName(add.getTableName().toLowerCase()); + boolean flag = baseMapper.insertOrUpdate(add); + if (baseMapper.insertOrUpdate(add)) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 批量删除流程定义配置 + */ + @Override + public Boolean deleteByIds(Collection ids) { + return baseMapper.deleteBatchIds(ids) > 0; + } + + @Override + public Boolean deleteByDefIds(Collection ids) { + return baseMapper.delete(new LambdaQueryWrapper().in(WfDefinitionConfig::getDefinitionId, ids)) > 0; + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfFormManageServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfFormManageServiceImpl.java new file mode 100644 index 000000000..e0850d7ae --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfFormManageServiceImpl.java @@ -0,0 +1,111 @@ +package org.dromara.workflow.service.impl; + +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import org.dromara.workflow.common.enums.FormTypeEnum; +import org.springframework.stereotype.Service; +import org.dromara.workflow.domain.bo.WfFormManageBo; +import org.dromara.workflow.domain.vo.WfFormManageVo; +import org.dromara.workflow.domain.WfFormManage; +import org.dromara.workflow.mapper.WfFormManageMapper; +import org.dromara.workflow.service.IWfFormManageService; + +import java.util.List; +import java.util.Collection; + +/** + * 表单管理Service业务层处理 + * + * @author may + * @date 2024-03-29 + */ +@RequiredArgsConstructor +@Service +public class WfFormManageServiceImpl implements IWfFormManageService { + + private final WfFormManageMapper baseMapper; + + /** + * 查询表单管理 + */ + @Override + public WfFormManageVo queryById(Long id) { + return baseMapper.selectVoById(id); + } + + @Override + public List queryByIds(List ids) { + return baseMapper.selectVoBatchIds(ids); + } + + /** + * 查询表单管理列表 + */ + @Override + public TableDataInfo queryPageList(WfFormManageBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + @Override + public List selectList() { + List wfFormManageVos = baseMapper.selectVoList(new LambdaQueryWrapper().orderByDesc(WfFormManage::getUpdateTime)); + for (WfFormManageVo wfFormManageVo : wfFormManageVos) { + wfFormManageVo.setFormTypeName(FormTypeEnum.findByType(wfFormManageVo.getFormType())); + } + return wfFormManageVos; + } + + /** + * 查询表单管理列表 + */ + @Override + public List queryList(WfFormManageBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(WfFormManageBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.like(StringUtils.isNotBlank(bo.getFormName()), WfFormManage::getFormName, bo.getFormName()); + lqw.eq(StringUtils.isNotBlank(bo.getFormType()), WfFormManage::getFormType, bo.getFormType()); + return lqw; + } + + /** + * 新增表单管理 + */ + @Override + public Boolean insertByBo(WfFormManageBo bo) { + WfFormManage add = MapstructUtils.convert(bo, WfFormManage.class); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改表单管理 + */ + @Override + public Boolean updateByBo(WfFormManageBo bo) { + WfFormManage update = MapstructUtils.convert(bo, WfFormManage.class); + return baseMapper.updateById(update) > 0; + } + + /** + * 批量删除表单管理 + */ + @Override + public Boolean deleteByIds(Collection ids) { + return baseMapper.deleteBatchIds(ids) > 0; + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfNodeConfigServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfNodeConfigServiceImpl.java new file mode 100644 index 000000000..07a1d6337 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfNodeConfigServiceImpl.java @@ -0,0 +1,75 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.workflow.domain.vo.WfFormManageVo; +import org.dromara.workflow.service.IWfFormManageService; +import org.springframework.stereotype.Service; +import org.dromara.workflow.domain.vo.WfNodeConfigVo; +import org.dromara.workflow.domain.WfNodeConfig; +import org.dromara.workflow.mapper.WfNodeConfigMapper; +import org.dromara.workflow.service.IWfNodeConfigService; + +import java.util.Collection; +import java.util.List; + +/** + * 节点配置Service业务层处理 + * + * @author may + * @date 2024-03-30 + */ +@RequiredArgsConstructor +@Service +public class WfNodeConfigServiceImpl implements IWfNodeConfigService { + + private final WfNodeConfigMapper baseMapper; + private final IWfFormManageService iWfFormManageService; + + /** + * 查询节点配置 + */ + @Override + public WfNodeConfigVo queryById(Long id) { + return baseMapper.selectVoById(id); + } + + /** + * 保存节点配置 + */ + @Override + public Boolean saveOrUpdate(List list) { + return baseMapper.insertOrUpdateBatch(list); + } + + /** + * 批量删除节点配置 + */ + @Override + public Boolean deleteByIds(Collection ids) { + return baseMapper.deleteBatchIds(ids) > 0; + } + + + + @Override + public Boolean deleteByDefIds(Collection ids) { + return baseMapper.delete(new LambdaQueryWrapper().in(WfNodeConfig::getDefinitionId, ids)) > 0; + } + + @Override + public List selectByDefIds(Collection ids) { + List wfNodeConfigVos = baseMapper.selectVoList(new LambdaQueryWrapper().in(WfNodeConfig::getDefinitionId, ids)); + if (CollUtil.isNotEmpty(wfNodeConfigVos)) { + List formIds = StreamUtils.toList(wfNodeConfigVos, WfNodeConfigVo::getFormId); + List wfFormManageVos = iWfFormManageService.queryByIds(formIds); + for (WfNodeConfigVo wfNodeConfigVo : wfNodeConfigVos) { + wfFormManageVos.stream().filter(e -> ObjectUtil.equals(e.getId(), wfNodeConfigVo.getFormId())).findFirst().ifPresent(wfNodeConfigVo::setWfFormManageVo); + } + } + return wfNodeConfigVos; + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfTaskBackNodeServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfTaskBackNodeServiceImpl.java new file mode 100644 index 000000000..b65642939 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfTaskBackNodeServiceImpl.java @@ -0,0 +1,141 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.workflow.domain.WfTaskBackNode; +import org.dromara.workflow.domain.vo.MultiInstanceVo; +import org.dromara.workflow.mapper.WfTaskBackNodeMapper; +import org.dromara.workflow.service.IWfTaskBackNodeService; +import org.dromara.workflow.utils.WorkflowUtils; +import org.flowable.task.api.Task; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; + +import static org.dromara.workflow.common.constant.FlowConstant.MULTI_INSTANCE; +import static org.dromara.workflow.common.constant.FlowConstant.USER_TASK; + + +/** + * 节点驳回记录Service业务层处理 + * + * @author may + * @date 2024-03-13 + */ +@RequiredArgsConstructor +@Service +public class WfTaskBackNodeServiceImpl implements IWfTaskBackNodeService { + + private final WfTaskBackNodeMapper wfTaskBackNodeMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + public void recordExecuteNode(Task task) { + List list = getListByInstanceId(task.getProcessInstanceId()); + WfTaskBackNode wfTaskBackNode = new WfTaskBackNode(); + wfTaskBackNode.setNodeId(task.getTaskDefinitionKey()); + wfTaskBackNode.setNodeName(task.getName()); + wfTaskBackNode.setInstanceId(task.getProcessInstanceId()); + wfTaskBackNode.setAssignee(String.valueOf(LoginHelper.getUserId())); + MultiInstanceVo multiInstance = WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey()); + if (ObjectUtil.isNotEmpty(multiInstance)) { + wfTaskBackNode.setTaskType(MULTI_INSTANCE); + } else { + wfTaskBackNode.setTaskType(USER_TASK); + } + if (CollectionUtil.isEmpty(list)) { + wfTaskBackNode.setOrderNo(0); + wfTaskBackNodeMapper.insert(wfTaskBackNode); + } else { + WfTaskBackNode taskNode = list.stream().filter(e -> e.getNodeId().equals(wfTaskBackNode.getNodeId()) && e.getOrderNo() == 0).findFirst().orElse(null); + if (ObjectUtil.isEmpty(taskNode)) { + wfTaskBackNode.setOrderNo(list.get(0).getOrderNo() + 1); + WfTaskBackNode node = getListByInstanceIdAndNodeId(wfTaskBackNode.getInstanceId(), wfTaskBackNode.getNodeId()); + if (ObjectUtil.isNotEmpty(node)) { + node.setAssignee(node.getAssignee() + StringUtils.SEPARATOR + LoginHelper.getUserId()); + wfTaskBackNodeMapper.updateById(node); + } else { + wfTaskBackNodeMapper.insert(wfTaskBackNode); + } + } + } + } + + @Override + public List getListByInstanceId(String processInstanceId) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(WfTaskBackNode::getInstanceId, processInstanceId); + wrapper.orderByDesc(WfTaskBackNode::getOrderNo); + return wfTaskBackNodeMapper.selectList(wrapper); + } + + @Override + public WfTaskBackNode getListByInstanceIdAndNodeId(String processInstanceId, String nodeId) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(WfTaskBackNode::getInstanceId, processInstanceId); + queryWrapper.eq(WfTaskBackNode::getNodeId, nodeId); + return wfTaskBackNodeMapper.selectOne(queryWrapper); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean deleteBackTaskNode(String processInstanceId, String targetActivityId) { + try { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(WfTaskBackNode::getInstanceId, processInstanceId); + queryWrapper.eq(WfTaskBackNode::getNodeId, targetActivityId); + WfTaskBackNode actTaskNode = wfTaskBackNodeMapper.selectOne(queryWrapper); + if (ObjectUtil.isNotNull(actTaskNode)) { + Integer orderNo = actTaskNode.getOrderNo(); + List taskNodeList = getListByInstanceId(processInstanceId); + List ids = new ArrayList<>(); + if (CollectionUtil.isNotEmpty(taskNodeList)) { + for (WfTaskBackNode taskNode : taskNodeList) { + if (taskNode.getOrderNo() >= orderNo) { + ids.add(taskNode.getId()); + } + } + } + if (CollectionUtil.isNotEmpty(ids)) { + wfTaskBackNodeMapper.deleteBatchIds(ids); + } + } + return true; + } catch (Exception e) { + e.printStackTrace(); + throw new ServiceException("删除失败"); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean deleteByInstanceId(String processInstanceId) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(WfTaskBackNode::getInstanceId, processInstanceId); + List list = wfTaskBackNodeMapper.selectList(wrapper); + int delete = wfTaskBackNodeMapper.delete(wrapper); + if (list.size() != delete) { + throw new ServiceException("删除失败"); + } + return true; + } + + @Override + public boolean deleteByInstanceIds(List processInstanceIds) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.in(WfTaskBackNode::getInstanceId, processInstanceIds); + List list = wfTaskBackNodeMapper.selectList(wrapper); + int delete = wfTaskBackNodeMapper.delete(wrapper); + if (list.size() != delete) { + throw new ServiceException("删除失败"); + } + return true; + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowUserServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowUserServiceImpl.java new file mode 100644 index 000000000..c4b221df8 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowUserServiceImpl.java @@ -0,0 +1,215 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.enums.UserStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.SysUserRole; +import org.dromara.system.domain.bo.SysUserBo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.mapper.SysUserMapper; +import org.dromara.system.mapper.SysUserRoleMapper; +import org.dromara.workflow.domain.bo.SysUserMultiBo; +import org.dromara.workflow.domain.vo.MultiInstanceVo; +import org.dromara.workflow.domain.vo.TaskVo; +import org.dromara.workflow.service.IWorkflowUserService; +import org.dromara.workflow.utils.QueryUtils; +import org.dromara.workflow.utils.WorkflowUtils; +import org.flowable.engine.RuntimeService; +import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior; +import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior; +import org.flowable.task.api.Task; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * 工作流用户选人管理 业务处理层 + * + * @author may + */ +@RequiredArgsConstructor +@Service +public class WorkflowUserServiceImpl implements IWorkflowUserService { + + private final SysUserMapper sysUserMapper; + private final SysUserRoleMapper sysUserRoleMapper; + private final RuntimeService runtimeService; + + /** + * 分页查询工作流选择加签人员 + * + * @param bo 参数 + * @param pageQuery 分页 + */ + @Override + @SuppressWarnings("unchecked") + public TableDataInfo getPageByAddMultiInstance(SysUserMultiBo bo, PageQuery pageQuery) { + Task task = QueryUtils.taskQuery().taskId(bo.getTaskId()).singleResult(); + if (task == null) { + throw new ServiceException("任务不存在"); + } + MultiInstanceVo multiInstance = WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey()); + if (multiInstance == null) { + return TableDataInfo.build(); + } + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); + //检索条件 + queryWrapper.eq(StringUtils.isNotEmpty(bo.getDeptId()), SysUser::getDeptId, bo.getDeptId()); + queryWrapper.eq(SysUser::getStatus, UserStatus.OK.getCode()); + if (multiInstance.getType() instanceof SequentialMultiInstanceBehavior) { + List assigneeList = (List) runtimeService.getVariable(task.getExecutionId(), multiInstance.getAssigneeList()); + queryWrapper.notIn(CollectionUtil.isNotEmpty(assigneeList), SysUser::getUserId, assigneeList); + } else { + List list = QueryUtils.taskQuery(task.getProcessInstanceId()).list(); + List userIds = StreamUtils.toList(list, e -> Long.valueOf(e.getAssignee())); + queryWrapper.notIn(CollectionUtil.isNotEmpty(userIds), SysUser::getUserId, userIds); + } + queryWrapper.like(StringUtils.isNotEmpty(bo.getUserName()), SysUser::getUserName, bo.getUserName()); + queryWrapper.like(StringUtils.isNotEmpty(bo.getNickName()), SysUser::getNickName, bo.getNickName()); + Page page = new Page<>(pageQuery.getFirstNum(), pageQuery.getPageSize()); + Page userPage = sysUserMapper.selectVoPage(page, queryWrapper); + return TableDataInfo.build(recordPage(userPage)); + } + + /** + * 查询工作流选择减签人员 + * + * @param taskId 任务id 任务id + */ + @Override + @SuppressWarnings("unchecked") + public List getListByDeleteMultiInstance(String taskId) { + Task task = QueryUtils.taskQuery().taskId(taskId).singleResult(); + List taskList = QueryUtils.taskQuery(task.getProcessInstanceId()).list(); + MultiInstanceVo multiInstance = WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey()); + List taskListVo = new ArrayList<>(); + if (multiInstance == null) { + return Collections.emptyList(); + } + List assigneeList = new ArrayList<>(); + if (multiInstance.getType() instanceof SequentialMultiInstanceBehavior) { + List variable = (List) runtimeService.getVariable(task.getExecutionId(), multiInstance.getAssigneeList()); + for (Object o : variable) { + assigneeList.add(Long.valueOf(o.toString())); + } + } + + if (multiInstance.getType() instanceof SequentialMultiInstanceBehavior) { + List userIds = StreamUtils.filter(assigneeList, e -> !String.valueOf(e).equals(task.getAssignee())); + List sysUsers = null; + if (CollectionUtil.isNotEmpty(userIds)) { + sysUsers = sysUserMapper.selectVoBatchIds(userIds); + } + for (Long userId : userIds) { + TaskVo taskVo = new TaskVo(); + taskVo.setId("串行会签"); + taskVo.setExecutionId("串行会签"); + taskVo.setProcessInstanceId(task.getProcessInstanceId()); + taskVo.setName(task.getName()); + taskVo.setAssignee(userId); + if (CollectionUtil.isNotEmpty(sysUsers)) { + sysUsers.stream().filter(u -> u.getUserId().toString().equals(userId.toString())).findFirst().ifPresent(u -> taskVo.setAssigneeName(u.getNickName())); + } + taskListVo.add(taskVo); + } + return taskListVo; + } else if (multiInstance.getType() instanceof ParallelMultiInstanceBehavior) { + List tasks = StreamUtils.filter(taskList, e -> StringUtils.isBlank(e.getParentTaskId()) && !e.getExecutionId().equals(task.getExecutionId()) && e.getTaskDefinitionKey().equals(task.getTaskDefinitionKey())); + if (CollectionUtil.isNotEmpty(tasks)) { + List userIds = StreamUtils.toList(tasks, e -> Long.valueOf(e.getAssignee())); + List sysUsers = null; + if (CollectionUtil.isNotEmpty(userIds)) { + sysUsers = sysUserMapper.selectVoBatchIds(userIds); + } + for (Task t : tasks) { + TaskVo taskVo = new TaskVo(); + taskVo.setId(t.getId()); + taskVo.setExecutionId(t.getExecutionId()); + taskVo.setProcessInstanceId(t.getProcessInstanceId()); + taskVo.setName(t.getName()); + taskVo.setAssignee(Long.valueOf(t.getAssignee())); + if (CollectionUtil.isNotEmpty(sysUsers)) { + sysUsers.stream().filter(u -> u.getUserId().toString().equals(t.getAssignee())).findFirst().ifPresent(e -> taskVo.setAssigneeName(e.getNickName())); + } + taskListVo.add(taskVo); + } + return taskListVo; + } + } + return Collections.emptyList(); + } + + /** + * 翻译部门 + * + * @param page 用户分页数据 + */ + private Page recordPage(Page page) { + List records = page.getRecords(); + if (CollUtil.isEmpty(records)) { + return page; + } + List collectDeptId = StreamUtils.toList(records, SysUserVo::getDeptId); + if (CollUtil.isEmpty(collectDeptId)) { + return page; + } + page.setRecords(records); + return page; + } + + /** + * 按照用户id查询用户 + * + * @param userIds 用户id + */ + @Override + public List getUserListByIds(List userIds) { + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyList(); + } + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); + // 检索条件 + queryWrapper.eq(SysUser::getStatus, UserStatus.OK.getCode()); + queryWrapper.in(SysUser::getUserId, userIds); + return sysUserMapper.selectVoList(queryWrapper); + } + + /** + * 按照角色id查询关联用户id + * + * @param roleIds 角色id + */ + @Override + public List getUserRoleListByRoleIds(List roleIds) { + return sysUserRoleMapper.selectList(new LambdaQueryWrapper().in(SysUserRole::getRoleId, roleIds)); + } + + /** + * 分页查询用户 + * + * @param sysUserBo 参数 + * @param pageQuery 分页 + */ + @Override + public TableDataInfo getPageByUserList(SysUserBo sysUserBo, PageQuery pageQuery) { + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); + queryWrapper.eq(sysUserBo.getDeptId() != null, SysUser::getDeptId, sysUserBo.getDeptId()); + queryWrapper.eq(SysUser::getStatus, UserStatus.OK.getCode()); + queryWrapper.like(StringUtils.isNotEmpty(sysUserBo.getUserName()), SysUser::getUserName, sysUserBo.getUserName()); + queryWrapper.like(StringUtils.isNotEmpty(sysUserBo.getNickName()), SysUser::getNickName, sysUserBo.getNickName()); + Page userPage = sysUserMapper.selectVoPage(pageQuery.build(), queryWrapper); + return TableDataInfo.build(recordPage(userPage)); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/ModelUtils.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/ModelUtils.java new file mode 100644 index 000000000..7c5377ed7 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/ModelUtils.java @@ -0,0 +1,289 @@ +package org.dromara.workflow.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.workflow.domain.vo.MultiInstanceVo; +import org.flowable.bpmn.converter.BpmnXMLConverter; +import org.flowable.bpmn.model.*; +import org.flowable.bpmn.model.Process; +import org.flowable.editor.language.json.converter.BpmnJsonConverter; +import org.flowable.engine.ProcessEngine; + +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.rmi.ServerException; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 模型工具 + * + * @author may + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ModelUtils { + + private static final ProcessEngine PROCESS_ENGINE = SpringUtils.getBean(ProcessEngine.class); + + public static BpmnModel xmlToBpmnModel(String xml) throws IOException { + if (xml == null) { + throw new ServerException("xml不能为空"); + } + try { + InputStream inputStream = new ByteArrayInputStream(StrUtil.utf8Bytes(xml)); + XMLInputFactory factory = XMLInputFactory.newInstance(); + XMLStreamReader reader = factory.createXMLStreamReader(inputStream); + return new BpmnXMLConverter().convertToBpmnModel(reader); + } catch (XMLStreamException e) { + throw new ServerException(e.getMessage()); + } + } + + /** + * bpmnModel转为xml + * + * @param jsonBytes json + */ + public static byte[] bpmnJsonToXmlBytes(byte[] jsonBytes) throws IOException { + if (jsonBytes == null) { + return new byte[0]; + } + // 1. json字节码转成 BpmnModel 对象 + ObjectMapper objectMapper = JsonUtils.getObjectMapper(); + JsonNode jsonNode = objectMapper.readTree(jsonBytes); + BpmnModel bpmnModel = new BpmnJsonConverter().convertToBpmnModel(jsonNode); + + if (bpmnModel.getProcesses().isEmpty()) { + return new byte[0]; + } + // 2.将bpmnModel转为xml + return new BpmnXMLConverter().convertToXML(bpmnModel); + } + + /** + * xml转为bpmnModel + * + * @param xmlBytes xml + */ + public static BpmnModel xmlToBpmnModel(byte[] xmlBytes) throws XMLStreamException { + ByteArrayInputStream byteArrayInputStream = IoUtil.toStream(xmlBytes); + XMLInputFactory xif = XMLInputFactory.newInstance(); + XMLStreamReader xtr = xif.createXMLStreamReader(byteArrayInputStream); + return new BpmnXMLConverter().convertToBpmnModel(xtr); + } + + /** + * 校验模型 + * + * @param bpmnModel bpmn模型 + */ + public static void checkBpmnModel(BpmnModel bpmnModel) throws ServerException { + Collection flowElements = bpmnModel.getMainProcess().getFlowElements(); + + checkBpmnNode(flowElements, false); + + List subProcessList = flowElements.stream().filter(SubProcess.class::isInstance).map(SubProcess.class::cast).collect(Collectors.toList()); + if (!CollUtil.isEmpty(subProcessList)) { + for (SubProcess subProcess : subProcessList) { + Collection subProcessFlowElements = subProcess.getFlowElements(); + checkBpmnNode(subProcessFlowElements, true); + } + } + List multiInstanceVoList = new ArrayList<>(); + for (FlowElement flowElement : flowElements) { + if (flowElement instanceof UserTask && ObjectUtil.isNotEmpty(((UserTask) flowElement).getLoopCharacteristics()) && StringUtils.isNotBlank(((UserTask) flowElement).getLoopCharacteristics().getInputDataItem())) { + MultiInstanceVo multiInstanceVo = new MultiInstanceVo(); + multiInstanceVo.setAssigneeList(((UserTask) flowElement).getLoopCharacteristics().getInputDataItem()); + multiInstanceVoList.add(multiInstanceVo); + } + } + + if (CollectionUtil.isNotEmpty(multiInstanceVoList) && multiInstanceVoList.size() > 1) { + Map> assigneeListGroup = StreamUtils.groupByKey(multiInstanceVoList, MultiInstanceVo::getAssigneeList); + for (Map.Entry> entry : assigneeListGroup.entrySet()) { + List value = entry.getValue(); + if (CollectionUtil.isNotEmpty(value) && value.size() > 1) { + String key = entry.getKey(); + throw new ServerException("会签人员集合【" + key + "】重复,请重新设置集合KEY"); + } + } + } + } + + /** + * 校验bpmn节点是否合法 + * + * @param flowElements 节点集合 + * @param subtask 是否子流程 + */ + private static void checkBpmnNode(Collection flowElements, boolean subtask) throws ServerException { + + if (CollUtil.isEmpty(flowElements)) { + throw new ServerException(subtask ? "子流程必须存在节点" : "必须存在节点!"); + } + + List startEventList = flowElements.stream().filter(StartEvent.class::isInstance).map(StartEvent.class::cast).collect(Collectors.toList()); + if (CollUtil.isEmpty(startEventList)) { + throw new ServerException(subtask ? "子流程必须存在开始节点" : "必须存在开始节点!"); + } + + if (startEventList.size() > 1) { + throw new ServerException(subtask ? "子流程只能存在一个开始节点" : "只能存在一个开始节点!"); + } + + StartEvent startEvent = startEventList.get(0); + List outgoingFlows = startEvent.getOutgoingFlows(); + if (CollUtil.isEmpty(outgoingFlows)) { + throw new ServerException(subtask ? "子流程流程节点为空,请至少设计一条主线流程!" : "流程节点为空,请至少设计一条主线流程!"); + } + + FlowElement targetFlowElement = outgoingFlows.get(0).getTargetFlowElement(); + if (!(targetFlowElement instanceof UserTask) && !subtask) { + throw new ServerException("开始节点后第一个节点必须是用户任务!"); + } + //开始节点后第一个节点申请人节点 + if ((targetFlowElement instanceof UserTask) && !subtask) { + UserTask userTask = (UserTask) targetFlowElement; + if (StringUtils.isBlank(userTask.getFormKey())) { + throw new ServerException("申请人节点必须选择表单!"); + } + } + List endEventList = flowElements.stream().filter(EndEvent.class::isInstance).map(EndEvent.class::cast).collect(Collectors.toList()); + if (CollUtil.isEmpty(endEventList)) { + throw new ServerException(subtask ? "子流程必须存在结束节点!" : "必须存在结束节点!"); + } + } + + /** + * 获取流程全部用户节点 + * + * @param processDefinitionId 流程定义id + */ + public static List getUserTaskFlowElements(String processDefinitionId) { + BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId); + List list = new ArrayList<>(); + List processes = bpmnModel.getProcesses(); + Collection flowElements = processes.get(0).getFlowElements(); + buildUserTaskFlowElements(flowElements, list); + return list; + } + + /** + * 递归获取所有节点 + * + * @param flowElements 节点信息 + * @param list 集合 + */ + private static void buildUserTaskFlowElements(Collection flowElements, List list) { + for (FlowElement flowElement : flowElements) { + if (flowElement instanceof SubProcess) { + Collection subFlowElements = ((SubProcess) flowElement).getFlowElements(); + buildUserTaskFlowElements(subFlowElements, list); + } else if (flowElement instanceof UserTask) { + list.add((UserTask) flowElement); + } + } + } + + /** + * 获取流程全部节点 + * + * @param processDefinitionId 流程定义id + */ + public static List getFlowElements(String processDefinitionId) { + BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId); + List list = new ArrayList<>(); + List processes = bpmnModel.getProcesses(); + Collection flowElements = processes.get(0).getFlowElements(); + buildFlowElements(flowElements, list); + return list; + } + + /** + * 递归获取所有节点 + * + * @param flowElements 节点信息 + * @param list 集合 + */ + private static void buildFlowElements(Collection flowElements, List list) { + for (FlowElement flowElement : flowElements) { + list.add(flowElement); + if (flowElement instanceof SubProcess) { + Collection subFlowElements = ((SubProcess) flowElement).getFlowElements(); + buildFlowElements(subFlowElements, list); + } + } + } + + /** + * 获取全部扩展信息 + * + * @param processDefinitionId 流程定义id + */ + public static Map> getExtensionElements(String processDefinitionId) { + Map> map = new HashMap<>(); + List flowElements = getFlowElements(processDefinitionId); + for (FlowElement flowElement : flowElements) { + if (flowElement instanceof UserTask && CollUtil.isNotEmpty(flowElement.getExtensionElements())) { + map.putAll(flowElement.getExtensionElements()); + } + } + return map; + } + + /** + * 获取某个节点的扩展信息 + * + * @param processDefinitionId 流程定义id + * @param flowElementId 节点id + */ + public static Map> getExtensionElement(String processDefinitionId, String flowElementId) { + BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId); + Process process = bpmnModel.getMainProcess(); + FlowElement flowElement = process.getFlowElement(flowElementId); + return flowElement.getExtensionElements(); + } + + /** + * 判断当前节点是否为用户任务 + * + * @param processDefinitionId 流程定义id + * @param taskDefinitionKey 流程定义id + */ + public static boolean isUserTask(String processDefinitionId, String taskDefinitionKey) { + BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId); + FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(taskDefinitionKey); + return flowNode instanceof UserTask; + } + + /** + * 获取申请人节点 + * + * @param processDefinitionId 流程定义id + * @return 结果 + */ + public static UserTask getApplyUserTask(String processDefinitionId) { + BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId); + Collection flowElements = bpmnModel.getMainProcess().getFlowElements(); + List startEventList = flowElements.stream().filter(StartEvent.class::isInstance).map(StartEvent.class::cast).collect(Collectors.toList()); + StartEvent startEvent = startEventList.get(0); + List outgoingFlows = startEvent.getOutgoingFlows(); + FlowElement targetFlowElement = outgoingFlows.get(0).getTargetFlowElement(); + return (UserTask) targetFlowElement; + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/QueryUtils.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/QueryUtils.java new file mode 100644 index 000000000..944d9d78b --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/QueryUtils.java @@ -0,0 +1,154 @@ +package org.dromara.workflow.utils; + +import cn.hutool.core.bean.BeanUtil; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.workflow.domain.vo.TaskVo; +import org.flowable.engine.ProcessEngine; +import org.flowable.engine.history.HistoricActivityInstanceQuery; +import org.flowable.engine.history.HistoricProcessInstanceQuery; +import org.flowable.engine.repository.DeploymentQuery; +import org.flowable.engine.repository.ModelQuery; +import org.flowable.engine.repository.ProcessDefinitionQuery; +import org.flowable.engine.runtime.ProcessInstanceQuery; +import org.flowable.task.api.Task; +import org.flowable.task.api.TaskQuery; +import org.flowable.task.api.history.HistoricTaskInstanceQuery; + +import java.util.Collection; +import java.util.List; +import java.util.Set; + +/** + * 查询工具 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class QueryUtils { + + private static final ProcessEngine PROCESS_ENGINE = SpringUtils.getBean(ProcessEngine.class); + + public static ModelQuery modelQuery() { + ModelQuery query = PROCESS_ENGINE.getRepositoryService().createModelQuery(); + if (TenantHelper.isEnable()) { + query.modelTenantId(TenantHelper.getTenantId()); + } + return query; + } + + public static ProcessDefinitionQuery definitionQuery() { + ProcessDefinitionQuery query = PROCESS_ENGINE.getRepositoryService().createProcessDefinitionQuery(); + if (TenantHelper.isEnable()) { + query.processDefinitionTenantId(TenantHelper.getTenantId()); + } + return query; + } + + public static DeploymentQuery deploymentQuery() { + DeploymentQuery query = PROCESS_ENGINE.getRepositoryService().createDeploymentQuery(); + if (TenantHelper.isEnable()) { + query.deploymentTenantId(TenantHelper.getTenantId()); + } + return query; + } + + public static DeploymentQuery deploymentQuery(String deploymentId) { + return deploymentQuery().deploymentId(deploymentId); + } + + public static DeploymentQuery deploymentQuery(List deploymentIds) { + return deploymentQuery().deploymentIds(deploymentIds); + } + + public static HistoricTaskInstanceQuery hisTaskInstanceQuery() { + HistoricTaskInstanceQuery query = PROCESS_ENGINE.getHistoryService().createHistoricTaskInstanceQuery(); + if (TenantHelper.isEnable()) { + query.taskTenantId(TenantHelper.getTenantId()); + } + return query; + } + + public static HistoricTaskInstanceQuery hisTaskInstanceQuery(String processInstanceId) { + return hisTaskInstanceQuery().processInstanceId(processInstanceId); + } + + public static ProcessInstanceQuery instanceQuery() { + ProcessInstanceQuery query = PROCESS_ENGINE.getRuntimeService().createProcessInstanceQuery(); + if (TenantHelper.isEnable()) { + query.processInstanceTenantId(TenantHelper.getTenantId()); + } + return query; + } + + public static ProcessInstanceQuery instanceQuery(String processInstanceId) { + return instanceQuery().processInstanceId(processInstanceId); + } + + public static ProcessInstanceQuery instanceQuery(Set processInstanceIds) { + return instanceQuery().processInstanceIds(processInstanceIds); + } + + public static HistoricProcessInstanceQuery hisInstanceQuery() { + HistoricProcessInstanceQuery query = PROCESS_ENGINE.getHistoryService().createHistoricProcessInstanceQuery(); + if (TenantHelper.isEnable()) { + query.processInstanceTenantId(TenantHelper.getTenantId()); + } + return query; + } + + public static HistoricProcessInstanceQuery hisInstanceQuery(String processInstanceId) { + return hisInstanceQuery().processInstanceId(processInstanceId); + } + + public static HistoricProcessInstanceQuery hisInstanceQuery(Set processInstanceIds) { + return hisInstanceQuery().processInstanceIds(processInstanceIds); + } + + public static HistoricActivityInstanceQuery hisActivityInstanceQuery() { + HistoricActivityInstanceQuery query = PROCESS_ENGINE.getHistoryService().createHistoricActivityInstanceQuery(); + if (TenantHelper.isEnable()) { + query.activityTenantId(TenantHelper.getTenantId()); + } + return query; + } + + public static HistoricActivityInstanceQuery hisActivityInstanceQuery(String processInstanceId) { + return hisActivityInstanceQuery().processInstanceId(processInstanceId); + } + + public static TaskQuery taskQuery() { + TaskQuery query = PROCESS_ENGINE.getTaskService().createTaskQuery(); + if (TenantHelper.isEnable()) { + query.taskTenantId(TenantHelper.getTenantId()); + } + return query; + } + + public static TaskQuery taskQuery(String processInstanceId) { + return taskQuery().processInstanceId(processInstanceId); + } + + public static TaskQuery taskQuery(Collection processInstanceIds) { + return taskQuery().processInstanceIdIn(processInstanceIds); + } + + /** + * 按照任务id查询当前任务 + * + * @param taskId 任务id + */ + public static TaskVo getTask(String taskId) { + Task task = PROCESS_ENGINE.getTaskService().createTaskQuery().taskId(taskId).singleResult(); + if (task == null) { + return null; + } + TaskVo taskVo = BeanUtil.toBean(task, TaskVo.class); + taskVo.setMultiInstance(WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey()) != null); + String businessStatus = WorkflowUtils.getBusinessStatus(taskVo.getProcessInstanceId()); + taskVo.setBusinessStatus(businessStatus); + return taskVo; + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/WorkflowUtils.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/WorkflowUtils.java new file mode 100644 index 000000000..6979671e2 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/WorkflowUtils.java @@ -0,0 +1,342 @@ +package org.dromara.workflow.utils; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.reflect.ReflectUtils; +import org.dromara.common.mail.utils.MailUtils; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.common.websocket.dto.WebSocketMessageDto; +import org.dromara.common.websocket.utils.WebSocketUtils; +import org.dromara.system.domain.SysUserRole; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.workflow.common.constant.FlowConstant; +import org.dromara.workflow.common.enums.BusinessStatusEnum; +import org.dromara.workflow.common.enums.MessageTypeEnum; +import org.dromara.workflow.common.enums.TaskStatusEnum; +import org.dromara.workflow.domain.ActHiProcinst; +import org.dromara.workflow.domain.ActHiTaskinst; +import org.dromara.workflow.domain.vo.*; +import org.dromara.workflow.flowable.cmd.UpdateHiTaskInstCmd; +import org.dromara.workflow.mapper.ActHiTaskinstMapper; +import org.dromara.workflow.service.*; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.FlowNode; +import org.flowable.common.engine.api.delegate.Expression; +import org.flowable.engine.ProcessEngine; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior; +import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior; +import org.flowable.identitylink.api.history.HistoricIdentityLink; +import org.flowable.task.api.Task; +import org.flowable.task.api.history.HistoricTaskInstance; +import org.flowable.task.service.impl.persistence.entity.TaskEntity; + +import java.util.*; + +import static org.dromara.workflow.common.constant.FlowConstant.*; + +/** + * 工作流工具 + * + * @author may + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class WorkflowUtils { + + private static final ProcessEngine PROCESS_ENGINE = SpringUtils.getBean(ProcessEngine.class); + private static final IWorkflowUserService WORKFLOW_USER_SERVICE = SpringUtils.getBean(IWorkflowUserService.class); + private static final IActHiProcinstService ACT_HI_PROCINST_SERVICE = SpringUtils.getBean(IActHiProcinstService.class); + private static final ActHiTaskinstMapper ACT_HI_TASKINST_MAPPER = SpringUtils.getBean(ActHiTaskinstMapper.class); + + /** + * 创建一个新任务 + * + * @param currentTask 参数 + */ + public static TaskEntity createNewTask(Task currentTask) { + TaskEntity task = null; + if (ObjectUtil.isNotEmpty(currentTask)) { + task = (TaskEntity) PROCESS_ENGINE.getTaskService().newTask(); + task.setCategory(currentTask.getCategory()); + task.setDescription(currentTask.getDescription()); + task.setAssignee(currentTask.getAssignee()); + task.setName(currentTask.getName()); + task.setProcessDefinitionId(currentTask.getProcessDefinitionId()); + task.setProcessInstanceId(currentTask.getProcessInstanceId()); + task.setTaskDefinitionKey(currentTask.getTaskDefinitionKey()); + task.setPriority(currentTask.getPriority()); + task.setCreateTime(new Date()); + task.setTenantId(TenantHelper.getTenantId()); + PROCESS_ENGINE.getTaskService().saveTask(task); + } + if (ObjectUtil.isNotNull(task)) { + UpdateHiTaskInstCmd updateHiTaskInstCmd = new UpdateHiTaskInstCmd(Collections.singletonList(task.getId()), task.getProcessDefinitionId(), task.getProcessInstanceId()); + PROCESS_ENGINE.getManagementService().executeCommand(updateHiTaskInstCmd); + } + return task; + } + + /** + * 抄送任务 + * + * @param parentTaskList 父级任务 + * @param userIds 人员id + */ + public static void createCopyTask(List parentTaskList, List userIds) { + List list = new ArrayList<>(); + String tenantId = TenantHelper.getTenantId(); + for (Task parentTask : parentTaskList) { + for (Long userId : userIds) { + TaskEntity newTask = (TaskEntity) PROCESS_ENGINE.getTaskService().newTask(); + newTask.setParentTaskId(parentTask.getId()); + newTask.setAssignee(userId.toString()); + newTask.setName("【抄送】-" + parentTask.getName()); + newTask.setProcessDefinitionId(parentTask.getProcessDefinitionId()); + newTask.setProcessInstanceId(parentTask.getProcessInstanceId()); + newTask.setTaskDefinitionKey(parentTask.getTaskDefinitionKey()); + newTask.setTenantId(tenantId); + list.add(newTask); + } + } + PROCESS_ENGINE.getTaskService().bulkSaveTasks(list); + if (CollUtil.isNotEmpty(list) && CollUtil.isNotEmpty(parentTaskList)) { + String processInstanceId = parentTaskList.get(0).getProcessInstanceId(); + String processDefinitionId = parentTaskList.get(0).getProcessDefinitionId(); + List taskIds = StreamUtils.toList(list, Task::getId); + ActHiTaskinst actHiTaskinst = new ActHiTaskinst(); + actHiTaskinst.setProcDefId(processDefinitionId); + actHiTaskinst.setProcInstId(processInstanceId); + actHiTaskinst.setScopeType(TaskStatusEnum.COPY.getStatus()); + actHiTaskinst.setTenantId(tenantId); + LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); + updateWrapper.in(ActHiTaskinst::getId, taskIds); + ACT_HI_TASKINST_MAPPER.update(actHiTaskinst, updateWrapper); + for (Task task : list) { + PROCESS_ENGINE.getTaskService().addComment(task.getId(), task.getProcessInstanceId(), TaskStatusEnum.COPY.getStatus(), StrUtil.EMPTY); + } + } + } + + /** + * 获取当前任务参与者 + * + * @param taskId 任务id + */ + public static ParticipantVo getCurrentTaskParticipant(String taskId) { + ParticipantVo participantVo = new ParticipantVo(); + List linksForTask = PROCESS_ENGINE.getHistoryService().getHistoricIdentityLinksForTask(taskId); + Task task = QueryUtils.taskQuery().taskId(taskId).singleResult(); + if (task != null && CollUtil.isNotEmpty(linksForTask)) { + List groupList = StreamUtils.filter(linksForTask, e -> StringUtils.isNotBlank(e.getGroupId())); + if (CollUtil.isNotEmpty(groupList)) { + List groupIds = StreamUtils.toList(groupList, e -> Long.valueOf(e.getGroupId())); + List sysUserRoles = WORKFLOW_USER_SERVICE.getUserRoleListByRoleIds(groupIds); + if (CollUtil.isNotEmpty(sysUserRoles)) { + participantVo.setGroupIds(groupIds); + List userIdList = StreamUtils.toList(sysUserRoles, SysUserRole::getUserId); + List sysUsers = WORKFLOW_USER_SERVICE.getUserListByIds(userIdList); + if (CollUtil.isNotEmpty(sysUsers)) { + List userIds = StreamUtils.toList(sysUsers, SysUserVo::getUserId); + List nickNames = StreamUtils.toList(sysUsers, SysUserVo::getNickName); + participantVo.setCandidate(userIds); + participantVo.setCandidateName(nickNames); + participantVo.setClaim(!StringUtils.isBlank(task.getAssignee())); + } + } + } else { + List candidateList = StreamUtils.filter(linksForTask, e -> FlowConstant.CANDIDATE.equals(e.getType())); + List userIdList = new ArrayList<>(); + for (HistoricIdentityLink historicIdentityLink : linksForTask) { + try { + userIdList.add(Long.valueOf(historicIdentityLink.getUserId())); + } catch (NumberFormatException ignored) { + + } + } + List sysUsers = WORKFLOW_USER_SERVICE.getUserListByIds(userIdList); + if (CollUtil.isNotEmpty(sysUsers)) { + List userIds = StreamUtils.toList(sysUsers, SysUserVo::getUserId); + List nickNames = StreamUtils.toList(sysUsers, SysUserVo::getNickName); + participantVo.setCandidate(userIds); + participantVo.setCandidateName(nickNames); + // 判断当前任务是否具有多个办理人 + if (CollUtil.isNotEmpty(candidateList) && candidateList.size() > 1) { + // 如果 assignee 存在,则设置当前任务已经被认领 + participantVo.setClaim(StringUtils.isNotBlank(task.getAssignee())); + } + } + } + } + return participantVo; + } + + /** + * 判断当前节点是否为会签节点 + * + * @param processDefinitionId 流程定义id + * @param taskDefinitionKey 流程定义id + */ + public static MultiInstanceVo isMultiInstance(String processDefinitionId, String taskDefinitionKey) { + BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId); + FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(taskDefinitionKey); + MultiInstanceVo multiInstanceVo = new MultiInstanceVo(); + //判断是否为并行会签节点 + if (flowNode.getBehavior() instanceof ParallelMultiInstanceBehavior behavior && behavior.getCollectionExpression() != null) { + Expression collectionExpression = behavior.getCollectionExpression(); + String assigneeList = collectionExpression.getExpressionText(); + String assignee = behavior.getCollectionElementVariable(); + multiInstanceVo.setType(behavior); + multiInstanceVo.setAssignee(assignee); + multiInstanceVo.setAssigneeList(assigneeList); + return multiInstanceVo; + //判断是否为串行会签节点 + } else if (flowNode.getBehavior() instanceof SequentialMultiInstanceBehavior behavior && behavior.getCollectionExpression() != null) { + Expression collectionExpression = behavior.getCollectionExpression(); + String assigneeList = collectionExpression.getExpressionText(); + String assignee = behavior.getCollectionElementVariable(); + multiInstanceVo.setType(behavior); + multiInstanceVo.setAssignee(assignee); + multiInstanceVo.setAssigneeList(assigneeList); + return multiInstanceVo; + } + return null; + } + + /** + * 获取当前流程状态 + * + * @param taskId 任务id + */ + public static String getBusinessStatusByTaskId(String taskId) { + HistoricTaskInstance historicTaskInstance = QueryUtils.hisTaskInstanceQuery().taskId(taskId).singleResult(); + HistoricProcessInstance historicProcessInstance = QueryUtils.hisInstanceQuery(historicTaskInstance.getProcessInstanceId()).singleResult(); + return historicProcessInstance.getBusinessStatus(); + } + + /** + * 获取当前流程状态 + * + * @param processInstanceId 流程实例id + */ + public static String getBusinessStatus(String processInstanceId) { + HistoricProcessInstance historicProcessInstance = QueryUtils.hisInstanceQuery(processInstanceId).singleResult(); + return historicProcessInstance.getBusinessStatus(); + } + + /** + * 设置流程实例对象 + * + * @param obj 业务对象 + * @param businessKey 业务id + */ + public static void setProcessInstanceVo(Object obj, String businessKey) { + if (StringUtils.isBlank(businessKey) || obj == null) { + return; + } + ActHiProcinst actHiProcinst = ACT_HI_PROCINST_SERVICE.selectByBusinessKey(businessKey); + if (actHiProcinst == null) { + ProcessInstanceVo processInstanceVo = new ProcessInstanceVo(); + processInstanceVo.setBusinessStatus(BusinessStatusEnum.DRAFT.getStatus()); + ReflectUtils.invokeSetter(obj, PROCESS_INSTANCE_VO, processInstanceVo); + return; + } + ProcessInstanceVo processInstanceVo = BeanUtil.toBean(actHiProcinst, ProcessInstanceVo.class); + processInstanceVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(processInstanceVo.getBusinessStatus())); + ReflectUtils.invokeSetter(obj, PROCESS_INSTANCE_VO, processInstanceVo); + } + + /** + * 设置流程实例对象 + * + * @param obj 业务对象 + * @param idList 业务id + * @param fieldName 主键属性名称 + */ + public static void setProcessInstanceListVo(Object obj, List idList, String fieldName) { + if (CollUtil.isEmpty(idList) || obj == null) { + return; + } + List actHiProcinstList = ACT_HI_PROCINST_SERVICE.selectByBusinessKeyIn(idList); + if (obj instanceof Collection collection) { + for (Object o : collection) { + String fieldValue = ReflectUtils.invokeGetter(o, fieldName).toString(); + if (CollUtil.isEmpty(actHiProcinstList)) { + ProcessInstanceVo processInstanceVo = new ProcessInstanceVo(); + processInstanceVo.setBusinessStatus(BusinessStatusEnum.DRAFT.getStatus()); + processInstanceVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(processInstanceVo.getBusinessStatus())); + ReflectUtils.invokeSetter(o, PROCESS_INSTANCE_VO, processInstanceVo); + } else { + ActHiProcinst actHiProcinst = actHiProcinstList.stream().filter(e -> e.getBusinessKey().equals(fieldValue)).findFirst().orElse(null); + if (ObjectUtil.isNotEmpty(actHiProcinst)) { + ProcessInstanceVo processInstanceVo = BeanUtil.toBean(actHiProcinst, ProcessInstanceVo.class); + processInstanceVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(processInstanceVo.getBusinessStatus())); + ReflectUtils.invokeSetter(o, PROCESS_INSTANCE_VO, processInstanceVo); + } else { + ProcessInstanceVo processInstanceVo = new ProcessInstanceVo(); + processInstanceVo.setBusinessStatus(BusinessStatusEnum.DRAFT.getStatus()); + processInstanceVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(processInstanceVo.getBusinessStatus())); + ReflectUtils.invokeSetter(o, PROCESS_INSTANCE_VO, processInstanceVo); + } + } + } + } + } + + /** + * 发送消息 + * + * @param list 任务 + * @param name 流程名称 + * @param messageType 消息类型 + * @param message 消息内容,为空则发送默认配置的消息内容 + */ + public static void sendMessage(List list, String name, List messageType, String message) { + Set userIds = new HashSet<>(); + if (StringUtils.isBlank(message)) { + message = "有新的【" + name + "】单据已经提交至您的待办,请您及时处理。"; + } + for (Task t : list) { + ParticipantVo taskParticipant = WorkflowUtils.getCurrentTaskParticipant(t.getId()); + if (CollUtil.isNotEmpty(taskParticipant.getGroupIds())) { + List sysUserRoles = WORKFLOW_USER_SERVICE.getUserRoleListByRoleIds(taskParticipant.getGroupIds()); + if (CollUtil.isNotEmpty(sysUserRoles)) { + userIds.addAll(StreamUtils.toList(sysUserRoles, SysUserRole::getUserId)); + } + } + List candidate = taskParticipant.getCandidate(); + if (CollUtil.isNotEmpty(candidate)) { + userIds.addAll(candidate); + } + } + if (CollUtil.isNotEmpty(userIds)) { + List sysUserVoList = WORKFLOW_USER_SERVICE.getUserListByIds(new ArrayList<>(userIds)); + for (String code : messageType) { + MessageTypeEnum messageTypeEnum = MessageTypeEnum.getByCode(code); + if (ObjectUtil.isNotEmpty(messageTypeEnum)) { + switch (messageTypeEnum) { + case SYSTEM_MESSAGE: + WebSocketMessageDto dto = new WebSocketMessageDto(); + dto.setSessionKeys(new ArrayList<>(userIds)); + dto.setMessage(message); + WebSocketUtils.publishMessage(dto); + break; + case EMAIL_MESSAGE: + MailUtils.sendText(StreamUtils.join(sysUserVoList, SysUserVo::getEmail), "单据审批提醒", message); + break; + case SMS_MESSAGE: + //todo 短信发送 + break; + } + } + } + } + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/package-info.md b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/package-info.md new file mode 100644 index 000000000..c938b1e50 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/package-info.md @@ -0,0 +1,3 @@ +java包使用 `.` 分割 resource 目录使用 `/` 分割 +
+此文件目的 防止文件夹粘连找不到 `xml` 文件 \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActHiProcinstMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActHiProcinstMapper.xml new file mode 100644 index 000000000..dd0578576 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActHiProcinstMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActHiTaskinstMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActHiTaskinstMapper.xml new file mode 100644 index 000000000..7e73b603f --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActHiTaskinstMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActTaskMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActTaskMapper.xml new file mode 100644 index 000000000..d1508abca --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActTaskMapper.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/TestLeaveMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/TestLeaveMapper.xml new file mode 100644 index 000000000..d52f6b037 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/TestLeaveMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfCategoryMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfCategoryMapper.xml new file mode 100644 index 000000000..4375cb2dd --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfCategoryMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfDefinitionConfigMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfDefinitionConfigMapper.xml new file mode 100644 index 000000000..8d579f705 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfDefinitionConfigMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfFormManageMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfFormManageMapper.xml new file mode 100644 index 000000000..59221f82d --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfFormManageMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfNodeConfigMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfNodeConfigMapper.xml new file mode 100644 index 000000000..b65194f8b --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfNodeConfigMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfTaskBackNodeMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfTaskBackNodeMapper.xml new file mode 100644 index 000000000..4a9179b62 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfTaskBackNodeMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/script/bpmn/模型.zip b/script/bpmn/模型.zip new file mode 100644 index 000000000..6b8090a35 Binary files /dev/null and b/script/bpmn/模型.zip differ diff --git a/script/docker/docker-compose.yml b/script/docker/docker-compose.yml index 63d819e0c..bbac441be 100644 --- a/script/docker/docker-compose.yml +++ b/script/docker/docker-compose.yml @@ -100,7 +100,7 @@ services: network_mode: "host" ruoyi-server1: - image: ruoyi/ruoyi-server:5.1.2 + image: ruoyi/ruoyi-server:5.2.0 container_name: ruoyi-server1 environment: # 时区上海 @@ -115,7 +115,7 @@ services: network_mode: "host" ruoyi-server2: - image: ruoyi/ruoyi-server:5.1.2 + image: ruoyi/ruoyi-server:5.2.0 container_name: ruoyi-server2 environment: # 时区上海 @@ -130,7 +130,7 @@ services: network_mode: "host" ruoyi-monitor-admin: - image: ruoyi/ruoyi-monitor-admin:5.1.2 + image: ruoyi/ruoyi-monitor-admin:5.2.0 container_name: ruoyi-monitor-admin environment: # 时区上海 @@ -142,7 +142,7 @@ services: network_mode: "host" ruoyi-powerjob-server: - image: ruoyi/ruoyi-powerjob-server:5.1.2 + image: ruoyi/ruoyi-powerjob-server:5.2.0 container_name: ruoyi-powerjob-server environment: # 时区上海 @@ -156,3 +156,16 @@ services: privileged: true network_mode: "host" + ruoyi-easyretry-server: + image: ruoyi/ruoyi-easyretry-server:5.2.0 + container_name: ruoyi-easyretry-server + environment: + # 时区上海 + TZ: Asia/Shanghai + ports: + - "8800:8800" + - "1788:1788" + volumes: + - /docker/easyretry/logs/:/ruoyi/easyretry/logs + privileged: true + network_mode: "host" diff --git a/script/docker/nginx/conf/nginx.conf b/script/docker/nginx/conf/nginx.conf index 2aa6587da..512ce50c2 100644 --- a/script/docker/nginx/conf/nginx.conf +++ b/script/docker/nginx/conf/nginx.conf @@ -35,6 +35,10 @@ http { server 127.0.0.1:7700; } + upstream easyretry-server { + server 127.0.0.1:8800; + } + server { listen 80; server_name localhost; @@ -108,10 +112,18 @@ http { } # 解决 powerjob 代理之后静态文件无法访问的问题 请勿修改乱动 - location ~ ^/(js|css|jpg|png|svg|woff|ttf|ico|img)/ { + location ~ ^/(js|img|fonts)/ { proxy_pass http://powerjob-server; } + location /easy-retry/ { + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header REMOTE-HOST $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass http://easyretry-server/easy-retry/; + } + error_page 500 502 503 504 /50x.html; location = /50x.html { root html; diff --git a/script/sql/easy_retry.sql b/script/sql/easy_retry.sql new file mode 100644 index 000000000..c884c880a --- /dev/null +++ b/script/sql/easy_retry.sql @@ -0,0 +1,525 @@ +SET NAMES utf8mb4; + +CREATE TABLE `er_namespace` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `name` varchar(64) NOT NULL COMMENT '名称', + `unique_id` varchar(64) NOT NULL COMMENT '唯一id', + `description` varchar(256) NOT NULL DEFAULT '' COMMENT '描述', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + `deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT '逻辑删除 1、删除', + PRIMARY KEY (`id`), + KEY `idx_name` (`name`), + UNIQUE KEY `uk_unique_id` (`unique_id`) +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 COMMENT ='命名空间'; + +INSERT INTO `er_namespace` VALUES (1, 'Development', 'dev', '', now(), now(), 0); +INSERT INTO `er_namespace` VALUES (2, 'Production', 'prod', '', now(), now(), 0); + + +CREATE TABLE `er_group_config` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL DEFAULT '' COMMENT '组名称', + `description` varchar(256) NOT NULL DEFAULT '' COMMENT '组描述', + `token` varchar(64) NOT NULL DEFAULT 'ER_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT' COMMENT 'token', + `group_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '组状态 0、未启用 1、启用', + `version` int(11) NOT NULL COMMENT '版本号', + `group_partition` int(11) NOT NULL COMMENT '分区', + `id_generator_mode` tinyint(4) NOT NULL DEFAULT '1' COMMENT '唯一id生成模式 默认号段模式', + `init_scene` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否初始化场景 0:否 1:是', + `bucket_index` int(11) NOT NULL DEFAULT '0' COMMENT 'bucket', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_namespace_id_group_name` (`namespace_id`, `group_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='组配置' +; + +INSERT INTO `er_group_config` VALUES (1, 'dev', 'ruoyi_group', '', 'ER_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, 4, now(), now()); + + +CREATE TABLE `er_notify_config` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `scene_name` varchar(64) NOT NULL COMMENT '场景名称', + `notify_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '通知状态 0、未启用 1、启用', + `notify_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '通知类型 1、钉钉 2、邮件 3、企业微信', + `notify_attribute` varchar(512) NOT NULL COMMENT '配置属性', + `notify_threshold` int(11) NOT NULL DEFAULT '0' COMMENT '通知阈值', + `notify_scene` tinyint(4) NOT NULL DEFAULT '0' COMMENT '通知场景', + `rate_limiter_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '限流状态 0、未启用 1、启用', + `rate_limiter_threshold` int(11) NOT NULL DEFAULT '0' COMMENT '每秒限流阈值', + `description` varchar(256) NOT NULL DEFAULT '' COMMENT '描述', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_namespace_id_group_name_scene_name` (`namespace_id`, `group_name`, `scene_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='通知配置' +; + +CREATE TABLE `er_retry_dead_letter_0` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `unique_id` varchar(64) NOT NULL COMMENT '同组下id唯一', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `scene_name` varchar(64) NOT NULL COMMENT '场景名称', + `idempotent_id` varchar(64) NOT NULL COMMENT '幂等id', + `biz_no` varchar(64) NOT NULL DEFAULT '' COMMENT '业务编号', + `executor_name` varchar(512) NOT NULL DEFAULT '' COMMENT '执行器名称', + `args_str` text NOT NULL COMMENT '执行方法参数', + `ext_attrs` text NOT NULL COMMENT '扩展字段', + `task_type` tinyint(4) NOT NULL DEFAULT '1' COMMENT '任务类型 1、重试数据 2、回调数据', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`), + KEY `idx_namespace_id_group_name_scene_name` (`namespace_id`, `group_name`, `scene_name`), + KEY `idx_idempotent_id` (`idempotent_id`), + KEY `idx_biz_no` (`biz_no`), + KEY `idx_create_dt` (`create_dt`), + UNIQUE KEY `uk_namespace_id_group_name_unique_id` (`namespace_id`, `group_name`, `unique_id`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='死信队列表' +; + +CREATE TABLE `er_retry_task_0` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `unique_id` varchar(64) NOT NULL COMMENT '同组下id唯一', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `scene_name` varchar(64) NOT NULL COMMENT '场景名称', + `idempotent_id` varchar(64) NOT NULL COMMENT '幂等id', + `biz_no` varchar(64) NOT NULL DEFAULT '' COMMENT '业务编号', + `executor_name` varchar(512) NOT NULL DEFAULT '' COMMENT '执行器名称', + `args_str` text NOT NULL COMMENT '执行方法参数', + `ext_attrs` text NOT NULL COMMENT '扩展字段', + `next_trigger_at` datetime NOT NULL COMMENT '下次触发时间', + `retry_count` int(11) NOT NULL DEFAULT '0' COMMENT '重试次数', + `retry_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '重试状态 0、重试中 1、成功 2、最大重试次数', + `task_type` tinyint(4) NOT NULL DEFAULT '1' COMMENT '任务类型 1、重试数据 2、回调数据', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_namespace_id_group_name_scene_name` (`namespace_id`, `group_name`, `scene_name`), + KEY `idx_namespace_id_group_name_task_type` (`namespace_id`, `group_name`, `task_type`), + KEY `idx_namespace_id_group_name_retry_status` (`namespace_id`, `group_name`, `retry_status`), + KEY `idx_idempotent_id` (`idempotent_id`), + KEY `idx_biz_no` (`biz_no`), + KEY `idx_create_dt` (`create_dt`), + UNIQUE KEY `uk_name_unique_id` (`namespace_id`, `group_name`, `unique_id`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='任务表' +; + +CREATE TABLE `er_retry_task_log` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `unique_id` varchar(64) NOT NULL COMMENT '同组下id唯一', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `scene_name` varchar(64) NOT NULL COMMENT '场景名称', + `idempotent_id` varchar(64) NOT NULL COMMENT '幂等id', + `biz_no` varchar(64) NOT NULL DEFAULT '' COMMENT '业务编号', + `executor_name` varchar(512) NOT NULL DEFAULT '' COMMENT '执行器名称', + `args_str` text NOT NULL COMMENT '执行方法参数', + `ext_attrs` text NOT NULL COMMENT '扩展字段', + `retry_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '重试状态 0、重试中 1、成功 2、最大次数', + `task_type` tinyint(4) NOT NULL DEFAULT '1' COMMENT '任务类型 1、重试数据 2、回调数据', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_group_name_scene_name` (`namespace_id`, `group_name`, `scene_name`), + KEY `idx_retry_status` (`retry_status`), + KEY `idx_idempotent_id` (`idempotent_id`), + KEY `idx_unique_id` (`unique_id`), + KEY `idx_biz_no` (`biz_no`), + KEY `idx_create_dt` (`create_dt`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='任务日志基础信息表' +; + +CREATE TABLE `er_retry_task_log_message` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `unique_id` varchar(64) NOT NULL COMMENT '同组下id唯一', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `message` longtext NOT NULL COMMENT '异常信息', + `log_num` int(11) NOT NULL DEFAULT 1 COMMENT '日志数量', + `real_time` bigint(13) NOT NULL DEFAULT 0 COMMENT '上报时间', + PRIMARY KEY (`id`), + KEY `idx_namespace_id_group_name_scene_name` (`namespace_id`, `group_name`, `unique_id`), + KEY `idx_create_dt` (`create_dt`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='任务调度日志信息记录表' +; + +CREATE TABLE `er_scene_config` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `scene_name` varchar(64) NOT NULL COMMENT '场景名称', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `scene_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '组状态 0、未启用 1、启用', + `max_retry_count` int(11) NOT NULL DEFAULT '5' COMMENT '最大重试次数', + `back_off` tinyint(4) NOT NULL DEFAULT '1' COMMENT '1、默认等级 2、固定间隔时间 3、CRON 表达式', + `trigger_interval` varchar(16) NOT NULL DEFAULT '' COMMENT '间隔时长', + `deadline_request` bigint(20) unsigned NOT NULL DEFAULT '60000' COMMENT 'Deadline Request 调用链超时 单位毫秒', + `executor_timeout` int(11) unsigned NOT NULL DEFAULT '5' COMMENT '任务执行超时时间,单位秒', + `route_key` tinyint(4) NOT NULL DEFAULT '4' COMMENT '路由策略', + `description` varchar(256) NOT NULL DEFAULT '' COMMENT '描述', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_namespace_id_group_name_scene_name` (`namespace_id`, `group_name`, `scene_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='场景配置' +; + +CREATE TABLE `er_server_node` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `host_id` varchar(64) NOT NULL COMMENT '主机id', + `host_ip` varchar(64) NOT NULL COMMENT '机器ip', + `context_path` varchar(256) NOT NULL DEFAULT '/' COMMENT '客户端上下文路径 server.servlet.context-path', + `host_port` int(16) NOT NULL COMMENT '机器端口', + `expire_at` datetime NOT NULL COMMENT '过期时间', + `node_type` tinyint(4) NOT NULL COMMENT '节点类型 1、客户端 2、是服务端', + `ext_attrs` varchar(256) NULL default '' COMMENT '扩展字段', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`), + KEY `idx_expire_at_node_type` (`expire_at`, `node_type`), + UNIQUE KEY `uk_host_id_host_ip` (`host_id`, `host_ip`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='服务器节点' +; + +CREATE TABLE `er_distributed_lock` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `name` varchar(64) NOT NULL COMMENT '锁名称', + `lock_until` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '锁定时长', + `locked_at` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '锁定时间', + `locked_by` varchar(255) NOT NULL COMMENT '锁定者', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_name` (`name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='锁定表' +; + +CREATE TABLE `er_system_user` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `username` varchar(64) NOT NULL COMMENT '账号', + `password` varchar(128) NOT NULL COMMENT '密码', + `role` tinyint(4) NOT NULL DEFAULT '0' COMMENT '角色:1-普通用户、2-管理员', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_username` (`username`) USING BTREE +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 COMMENT ='系统用户表'; + +-- pwd: admin +INSERT INTO `er_system_user` VALUES (1, 'admin', '465c194afb65670f38322df087f0a9bb225cc257e43eb4ac5a0c98ef5b3173ac', 2, now(), now()); + +CREATE TABLE `er_system_user_permission` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `system_user_id` bigint(20) NOT NULL COMMENT '系统用户id', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_namespace_id_group_name_system_user_id` (`namespace_id`, `group_name`, `system_user_id`) +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 COMMENT ='系统用户权限表'; + +CREATE TABLE `er_sequence_alloc` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL DEFAULT '' COMMENT '组名称', + `max_id` bigint(20) NOT NULL DEFAULT '1' COMMENT '最大id', + `step` int(11) NOT NULL DEFAULT '100' COMMENT '步长', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_namespace_id_group_name` (`namespace_id`, `group_name`) +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 COMMENT ='号段模式序号ID分配表'; + +-- 分布式调度DDL +CREATE TABLE `er_job` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `job_name` varchar(64) NOT NULL COMMENT '名称', + `args_str` text DEFAULT NULL COMMENT '执行方法参数', + `args_type` tinyint(4) NOT NULL DEFAULT '1' COMMENT '参数类型 ', + `next_trigger_at` bigint(13) NOT NULL COMMENT '下次触发时间', + `job_status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '任务状态 0、关闭、1、开启', + `task_type` tinyint(4) NOT NULL DEFAULT '1' COMMENT '任务类型 1、集群 2、广播 3、切片', + `route_key` tinyint(4) NOT NULL DEFAULT '4' COMMENT '路由策略', + `executor_type` tinyint(4) NOT NULL DEFAULT '1' COMMENT '执行器类型', + `executor_info` varchar(255) DEFAULT NULL COMMENT '执行器名称', + `trigger_type` tinyint(4) NOT NULL COMMENT '触发类型 1.CRON 表达式 2. 固定时间', + `trigger_interval` varchar(255) NOT NULL COMMENT '间隔时长', + `block_strategy` tinyint(4) NOT NULL DEFAULT '1' COMMENT '阻塞策略 1、丢弃 2、覆盖 3、并行', + `executor_timeout` int(11) NOT NULL DEFAULT '0' COMMENT '任务执行超时时间,单位秒', + `max_retry_times` int(11) NOT NULL DEFAULT '0' COMMENT '最大重试次数', + `parallel_num` int(11) NOT NULL DEFAULT '1' COMMENT '并行数', + `retry_interval` int(11) NOT NULL DEFAULT '0' COMMENT '重试间隔(s)', + `bucket_index` int(11) NOT NULL DEFAULT '0' COMMENT 'bucket', + `resident` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否是常驻任务', + `description` varchar(256) NOT NULL DEFAULT '' COMMENT '描述', + `ext_attrs` varchar(256) NULL default '' COMMENT '扩展字段', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + `deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT '逻辑删除 1、删除', + PRIMARY KEY (`id`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`), + KEY `idx_job_status_bucket_index` (`job_status`, `bucket_index`), + KEY `idx_create_dt` (`create_dt`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='任务信息'; + +CREATE TABLE `er_job_log_message` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `job_id` bigint(20) NOT NULL COMMENT '任务信息id', + `task_batch_id` bigint(20) NOT NULL COMMENT '任务批次id', + `task_id` bigint(20) NOT NULL COMMENT '调度任务id', + `message` longtext NOT NULL COMMENT '调度信息', + `log_num` int(11) NOT NULL DEFAULT 1 COMMENT '日志数量', + `real_time` bigint(13) NOT NULL DEFAULT 0 COMMENT '上报时间', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `ext_attrs` varchar(256) NULL default '' COMMENT '扩展字段', + PRIMARY KEY (`id`), + KEY `idx_task_batch_id_task_id` (`task_batch_id`, `task_id`), + KEY `idx_create_dt` (`create_dt`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='调度日志'; + +CREATE TABLE `er_job_task` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `job_id` bigint(20) NOT NULL COMMENT '任务信息id', + `task_batch_id` bigint(20) NOT NULL COMMENT '调度任务id', + `parent_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '父执行器id', + `task_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '执行的状态 0、失败 1、成功', + `retry_count` int(11) NOT NULL DEFAULT '0' COMMENT '重试次数', + `client_info` varchar(128) DEFAULT NULL COMMENT '客户端地址 clientId#ip:port', + `result_message` text NOT NULL COMMENT '执行结果', + `args_str` text DEFAULT NULL COMMENT '执行方法参数', + `args_type` tinyint(4) NOT NULL DEFAULT '1' COMMENT '参数类型 ', + `ext_attrs` varchar(256) NULL default '' COMMENT '扩展字段', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_task_batch_id_task_status` (`task_batch_id`, `task_status`), + KEY `idx_create_dt` (`create_dt`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='任务实例'; + +CREATE TABLE `er_job_task_batch` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `job_id` bigint(20) NOT NULL COMMENT '任务id', + `workflow_node_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '工作流节点id', + `parent_workflow_node_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '工作流任务父批次id', + `workflow_task_batch_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '工作流任务批次id', + `task_batch_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '任务批次状态 0、失败 1、成功', + `operation_reason` tinyint(4) NOT NULL DEFAULT '0' COMMENT '操作原因', + `execution_at` bigint(13) NOT NULL DEFAULT '0' COMMENT '任务执行时间', + `system_task_type` tinyint(4) NOT NULL DEFAULT '3' COMMENT '任务类型 3、JOB任务 4、WORKFLOW任务', + `parent_id` varchar(64) NOT NULL DEFAULT '' COMMENT '父节点', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + `deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT '逻辑删除 1、删除', + `ext_attrs` varchar(256) NULL default '' COMMENT '扩展字段', + PRIMARY KEY (`id`), + KEY `idx_job_id_task_batch_status` (`job_id`, `task_batch_status`), + KEY `idx_create_dt` (`create_dt`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`), + KEY `idx_workflow_task_batch_id_workflow_node_id` (`workflow_task_batch_id`, `workflow_node_id`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='任务批次'; + +CREATE TABLE `er_job_notify_config` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `job_id` bigint(20) NOT NULL COMMENT '任务id', + `notify_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '通知状态 0、未启用 1、启用', + `notify_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '通知类型 1、钉钉 2、邮件 3、企业微信', + `notify_attribute` varchar(512) NOT NULL COMMENT '配置属性', + `notify_threshold` int(11) NOT NULL DEFAULT '0' COMMENT '通知阈值', + `notify_scene` tinyint(4) NOT NULL DEFAULT '0' COMMENT '通知场景', + `rate_limiter_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '限流状态 0、未启用 1、启用', + `rate_limiter_threshold` int(11) NOT NULL DEFAULT '0' COMMENT '每秒限流阈值', + `description` varchar(256) NOT NULL DEFAULT '' COMMENT '描述', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_namespace_id_group_name_job_id` (`namespace_id`, `group_name`, job_id) +) ENGINE = InnoDB + AUTO_INCREMENT = 4 + DEFAULT CHARSET = utf8mb4 COMMENT ='job通知配置'; + +CREATE TABLE `er_job_summary` +( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` VARCHAR(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '组名称', + `business_id` bigint NOT NULL COMMENT '业务id (job_id或workflow_id)', + `system_task_type` tinyint(4) NOT NULL DEFAULT '3' COMMENT '任务类型 3、JOB任务 4、WORKFLOW任务', + `trigger_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '统计时间', + `success_num` int NOT NULL DEFAULT '0' COMMENT '执行成功-日志数量', + `fail_num` int NOT NULL DEFAULT '0' COMMENT '执行失败-日志数量', + `fail_reason` varchar(512) NOT NULL DEFAULT '' COMMENT '失败原因', + `stop_num` int NOT NULL DEFAULT '0' COMMENT '执行失败-日志数量', + `stop_reason` varchar(512) NOT NULL DEFAULT '' COMMENT '失败原因', + `cancel_num` int NOT NULL DEFAULT '0' COMMENT '执行失败-日志数量', + `cancel_reason` varchar(512) NOT NULL DEFAULT '' COMMENT '失败原因', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_namespace_id_group_name_business_id` (`namespace_id`, `group_name`, business_id), + UNIQUE KEY `uk_trigger_at_system_task_type_business_id` (`trigger_at`, `system_task_type`, `business_id`) USING BTREE +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4 COMMENT ='DashBoard_Job'; + +CREATE TABLE `er_retry_summary` +( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` VARCHAR(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '组名称', + `scene_name` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '场景名称', + `trigger_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '统计时间', + `running_num` int NOT NULL DEFAULT '0' COMMENT '重试中-日志数量', + `finish_num` int NOT NULL DEFAULT '0' COMMENT '重试完成-日志数量', + `max_count_num` int NOT NULL DEFAULT '0' COMMENT '重试到达最大次数-日志数量', + `suspend_num` int NOT NULL DEFAULT '0' COMMENT '暂停重试-日志数量', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_trigger_at` (`trigger_at`), + UNIQUE KEY `uk_scene_name_trigger_at` (`namespace_id`, `group_name`, `scene_name`, `trigger_at`) USING BTREE +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4 COMMENT ='DashBoard_Retry'; + +CREATE TABLE `er_workflow` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `workflow_name` varchar(64) NOT NULL COMMENT '工作流名称', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `workflow_status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '工作流状态 0、关闭、1、开启', + `trigger_type` tinyint(4) NOT NULL COMMENT '触发类型 1.CRON 表达式 2. 固定时间', + `trigger_interval` varchar(255) NOT NULL COMMENT '间隔时长', + `next_trigger_at` bigint(13) NOT NULL COMMENT '下次触发时间', + `block_strategy` tinyint(4) NOT NULL DEFAULT '1' COMMENT '阻塞策略 1、丢弃 2、覆盖 3、并行', + `executor_timeout` int(11) NOT NULL DEFAULT '0' COMMENT '任务执行超时时间,单位秒', + `description` varchar(256) NOT NULL DEFAULT '' COMMENT '描述', + `flow_info` text DEFAULT NULL COMMENT '流程信息', + `bucket_index` int(11) NOT NULL DEFAULT '0' COMMENT 'bucket', + `version` int(11) NOT NULL COMMENT '版本号', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + `deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT '逻辑删除 1、删除', + `ext_attrs` varchar(256) NULL default '' COMMENT '扩展字段', + PRIMARY KEY (`id`), + KEY `idx_create_dt` (`create_dt`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='工作流'; + +CREATE TABLE `er_workflow_node` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `node_name` varchar(64) NOT NULL COMMENT '节点名称', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `job_id` bigint(20) NOT NULL COMMENT '任务信息id', + `workflow_id` bigint(20) NOT NULL COMMENT '工作流ID', + `node_type` tinyint(4) NOT NULL DEFAULT 1 COMMENT '1、任务节点 2、条件节点', + `expression_type` tinyint(4) NOT NULL DEFAULT 0 COMMENT '1、SpEl、2、Aviator 3、QL', + `fail_strategy` tinyint(4) NOT NULL DEFAULT 1 COMMENT '失败策略 1、跳过 2、阻塞', + `workflow_node_status` tinyint(4) NOT NULL DEFAULT 1 COMMENT '工作流节点状态 0、关闭、1、开启', + `priority_level` int(11) NOT NULL DEFAULT 1 COMMENT '优先级', + `node_info` text DEFAULT NULL COMMENT '节点信息 ', + `version` int(11) NOT NULL COMMENT '版本号', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + `deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT '逻辑删除 1、删除', + `ext_attrs` varchar(256) NULL default '' COMMENT '扩展字段', + PRIMARY KEY (`id`), + KEY `idx_create_dt` (`create_dt`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='工作流节点'; + +CREATE TABLE `er_workflow_task_batch` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `workflow_id` bigint(20) NOT NULL COMMENT '工作流任务id', + `task_batch_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '任务批次状态 0、失败 1、成功', + `operation_reason` tinyint(4) NOT NULL DEFAULT '0' COMMENT '操作原因', + `flow_info` text DEFAULT NULL COMMENT '流程信息', + `execution_at` bigint(13) NOT NULL DEFAULT '0' COMMENT '任务执行时间', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + `deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT '逻辑删除 1、删除', + `ext_attrs` varchar(256) NULL default '' COMMENT '扩展字段', + PRIMARY KEY (`id`), + KEY `idx_job_id_task_batch_status` (`workflow_id`, `task_batch_status`), + KEY `idx_create_dt` (`create_dt`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='工作流批次'; diff --git a/script/sql/flowable.sql b/script/sql/flowable.sql new file mode 100644 index 000000000..ce215a7dd --- /dev/null +++ b/script/sql/flowable.sql @@ -0,0 +1,175 @@ +insert into sys_menu values('11616', '工作流' , '0', '6', 'workflow', '', '', '1', '0', 'M', '0', '0', '', 'tree-table', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values('11617', '模型管理', '11616', '2', 'model', 'workflow/model/index', '', '1', '1', 'C', '0', '0', 'workflow:model:list', 'tree-table', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values('11618', '我的任务', '0', '7', 'task', '', '', '1', '0', 'M', '0', '0', '', 'tree-table', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values('11619', '我的待办', '11618', '2', 'taskWaiting', 'workflow/task/taskWaiting', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values('11632', '我的已办', '11618', '3', 'taskFinish', 'workflow/task/taskFinish', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values('11633', '我的抄送', '11618', '4', 'taskCopyList', 'workflow/task/taskCopyList', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values('11620', '流程定义', '11616', '3', 'processDefinition', 'workflow/processDefinition/index', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values('11621', '流程实例', '11630', '1', 'processInstance', 'workflow/processInstance/index', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values('11622', '流程分类', '11616', '1', 'category', 'workflow/category/index', '', '1', '0', 'C', '0', '0', 'workflow:category:list', 'tree-table', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values('11629', '我发起的', '11618', '1', 'myDocument', 'workflow/task/myDocument', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values('11630', '流程监控', '11616', '4', 'monitor', '', '', '1', '0', 'M', '0', '0', '', 'tree-table', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values('11631', '待办任务', '11630', '2', 'allTaskWaiting', 'workflow/task/allTaskWaiting', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, sysdate(), NULL, NULL, ''); + + +-- 流程分类管理相关按钮 +insert into sys_menu values ('11623', '流程分类查询', '11622', '1', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('11624', '流程分类新增', '11622', '2', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('11625', '流程分类修改', '11622', '3', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('11626', '流程分类删除', '11622', '4', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:remove','#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('11627', '流程分类导出', '11622', '5', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:export','#', 103, 1, sysdate(), null, null, ''); +-- 请假单信息 +create table test_leave +( + id bigint not null comment '主键', + leave_type varchar(255) not null comment '请假类型', + start_date datetime not null comment '开始时间', + end_date datetime not null comment '结束时间', + leave_days int(10) not null comment '请假天数', + remark varchar(255) null comment '请假原因', + create_dept bigint null comment '创建部门', + create_by bigint null comment '创建者', + create_time datetime null comment '创建时间', + update_by bigint null comment '更新者', + update_time datetime null comment '更新时间', + tenant_id varchar(20) null comment '租户编号', + PRIMARY KEY (id) USING BTREE +) ENGINE = InnoDB COMMENT = '请假申请表'; + +-- 流程分类信息表 +create table wf_category +( + id bigint not null comment '主键' + primary key, + category_name varchar(255) null comment '分类名称', + category_code varchar(255) null comment '分类编码', + parent_id bigint null comment '父级id', + sort_num int(19) null comment '排序', + tenant_id varchar(20) null comment '租户编号', + create_dept bigint null comment '创建部门', + create_by bigint null comment '创建者', + create_time datetime null comment '创建时间', + update_by bigint null comment '更新者', + update_time datetime null comment '更新时间', + constraint uni_category_code + unique (category_code) +) engine=innodb comment= '流程分类'; +INSERT INTO wf_category values (1, 'OA', 'OA', 0, 0, '000000', 103, 1, sysdate(), 1, sysdate()); + +create table wf_task_back_node +( + id bigint not null + primary key, + node_id varchar(255) not null comment '节点id', + node_name varchar(255) not null comment '节点名称', + order_no int not null comment '排序', + instance_id varchar(255) null comment '流程实例id', + task_type varchar(255) not null comment '节点类型', + assignee varchar(2000) not null comment '审批人', + tenant_id varchar(20) null comment '租户编号', + create_dept bigint null comment '创建部门', + create_by bigint null comment '创建者', + create_time datetime null comment '创建时间', + update_by bigint null comment '更新者', + update_time datetime null comment '更新时间' +) + comment '节点审批记录'; + +create table wf_definition_config +( + id bigint not null comment '主键' + primary key, + table_name varchar(255) not null comment '表名', + definition_id varchar(255) not null comment '流程定义ID', + process_key varchar(255) not null comment '流程KEY', + version int(10) not null comment '流程版本', + create_dept bigint null comment '创建部门', + create_by bigint null comment '创建者', + create_time datetime null comment '创建时间', + update_by bigint null comment '更新者', + update_time datetime null comment '更新时间', + remark varchar(500) default '' null comment '备注', + tenant_id varchar(20) null comment '租户编号', + constraint uni_definition_id + unique (definition_id) +) + comment '流程定义配置'; + +create table wf_form_manage +( + id bigint not null comment '主键' + primary key, + form_name varchar(255) not null comment '表单名称', + form_type varchar(255) not null comment '表单类型', + router varchar(255) not null comment '路由地址/表单ID', + remark varchar(500) null comment '备注', + tenant_id varchar(20) null comment '租户编号', + create_dept bigint null comment '创建部门', + create_by bigint null comment '创建者', + create_time datetime null comment '创建时间', + update_by bigint null comment '更新者', + update_time datetime null comment '更新时间' +) + comment '表单管理'; + +insert into wf_form_manage(id, form_name, form_type, router, remark, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1, '请假申请', 'static', '/demo/leaveEdit/index', NULL, '000000', 103, 1, sysdate(), 1, sysdate()); + +create table wf_node_config +( + id bigint not null comment '主键' + primary key, + form_id bigint null comment '表单id', + form_type varchar(255) null comment '表单类型', + node_name varchar(255) not null comment '节点名称', + node_id varchar(255) not null comment '节点id', + definition_id varchar(255) not null comment '流程定义id', + apply_user_task char(1) default '0' comment '是否为申请人节点 (0是 1否)', + create_dept bigint null comment '创建部门', + create_by bigint null comment '创建者', + create_time datetime null comment '创建时间', + update_by bigint null comment '更新者', + update_time datetime null comment '更新时间', + tenant_id varchar(20) null comment '租户编号' +) + comment '节点配置'; + + +INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11638, '请假申请', 5, 1, 'leave', 'workflow/leave/index', 1, 0, 'C', '0', '0', 'demo:leave:list', '#', 103, 1, sysdate(), NULL, NULL, '请假申请菜单'); +INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11639, '请假申请查询', 11638, 1, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:query', '#', 103, 1, sysdate(), NULL, NULL, ''); +INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11640, '请假申请新增', 11638, 2, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:add', '#', 103, 1, sysdate(), NULL, NULL, ''); +INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11641, '请假申请修改', 11638, 3, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:edit', '#', 103, 1, sysdate(), NULL, NULL, ''); +INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11642, '请假申请删除', 11638, 4, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:remove', '#', 103, 1, sysdate(), NULL, NULL, ''); +INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11643, '请假申请导出', 11638, 5, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:export', '#', 103, 1, sysdate(), NULL, NULL, ''); + +INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (13, '000000', '业务状态', 'wf_business_status', 103, 1, sysdate(), NULL, NULL, '业务状态列表'); +INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (14, '000000', '表单类型', 'wf_form_type', 103, 1, sysdate(), NULL, NULL, '表单类型列表'); + +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (39, '000000', 1, '已撤销', 'cancel', 'wf_business_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL, '已撤销'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (40, '000000', 2, '草稿', 'draft', 'wf_business_status', '', 'info', 'N', 103, 1, sysdate(), NULL, NULL, '草稿'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (41, '000000', 3, '待审核', 'waiting', 'wf_business_status', '', 'primary', 'N', 103, 1,sysdate(), NULL, NULL, '待审核'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (42, '000000', 4, '已完成', 'finish', 'wf_business_status', '', 'success', 'N', 103, 1, sysdate(), NULL, NULL, '已完成'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (43, '000000', 5, '已作废', 'invalid', 'wf_business_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL, '已作废'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (44, '000000', 6, '已退回', 'back', 'wf_business_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL, '已退回'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (45, '000000', 7, '已终止', 'termination', 'wf_business_status', '', 'danger', 'N', 103, 1,sysdate(), NULL, NULL, '已终止'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (46, '000000', 1, '自定义表单', 'static', 'wf_form_type', '', 'success', 'N', 103, 1, sysdate(), NULL, NULL, '自定义表单'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (47, '000000', 2, '动态表单', 'dynamic', 'wf_form_type', '', 'primary', 'N', 103, 1, sysdate(), NULL, NULL, '动态表单'); + +-- 表单管理 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(11628, '表单管理', '11616', '5', 'formManage', 'workflow/formManage/index', 1, 0, 'C', '0', '0', 'workflow:formManage:list', 'tree-table', 103, 1, sysdate(), null, null, '表单管理菜单'); + +-- 表单管理按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(11644, '表单管理查询', 11628, '1', '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:query', '', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(11645, '表单管理新增', 11628, '2', '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:add', '', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(11646, '表单管理修改', 11628, '3', '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:edit', '', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(11647, '表单管理删除', 11628, '4', '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:remove', '', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(11648, '表单管理导出', 11628, '5', '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:export', 'tree-table', 103, 1, sysdate(), null, null, ''); diff --git a/script/sql/oracle/easy_retry_oracle.sql b/script/sql/oracle/easy_retry_oracle.sql new file mode 100644 index 000000000..4c8c062af --- /dev/null +++ b/script/sql/oracle/easy_retry_oracle.sql @@ -0,0 +1,826 @@ +-- Oracle DDL + +-- er_namespace +CREATE TABLE er_namespace +( + id NUMBER GENERATED ALWAYS AS IDENTITY, + name VARCHAR2(64) NOT NULL, + unique_id VARCHAR2(64) NOT NULL, + description VARCHAR2(256) DEFAULT '', + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + deleted SMALLINT DEFAULT 0 +); + +CREATE UNIQUE INDEX uk_namespace_1 ON er_namespace (unique_id); + +COMMENT ON TABLE er_namespace IS '命名空间'; +COMMENT ON COLUMN er_namespace.id IS '主键'; +COMMENT ON COLUMN er_namespace.name IS '名称'; +COMMENT ON COLUMN er_namespace.unique_id IS '唯一id'; +COMMENT ON COLUMN er_namespace.description IS '描述'; +COMMENT ON COLUMN er_namespace.create_dt IS '创建时间'; +COMMENT ON COLUMN er_namespace.update_dt IS '修改时间'; +COMMENT ON COLUMN er_namespace.deleted IS '逻辑删除 1、删除'; + +-- id 为 IDENTITY 类型, 不能插入 +INSERT INTO er_namespace(name, unique_id, description, create_dt, update_dt, deleted) VALUES('Development', 'dev', '', SYSDATE, SYSDATE, 0 ); +INSERT INTO er_namespace(name, unique_id, description, create_dt, update_dt, deleted) VALUES ('Production', 'prod', '', sysdate, sysdate, 0); + +-- er_group_config +CREATE TABLE er_group_config +( + id NUMBER GENERATED ALWAYS AS IDENTITY, + namespace_id VARCHAR2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR2(64) NOT NULL, + description VARCHAR2(256) DEFAULT '', + token VARCHAR2(64) DEFAULT 'ER_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', + group_status SMALLINT DEFAULT 0, + version INT NOT NULL, + group_partition INT NOT NULL, + id_generator_mode SMALLINT DEFAULT 1, + init_scene SMALLINT DEFAULT 0, + bucket_index INT DEFAULT 0, + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_group_config_1 ON er_group_config (namespace_id, group_name); + +COMMENT ON TABLE er_group_config IS '组配置'; +COMMENT ON COLUMN er_group_config.id IS '主键'; +COMMENT ON COLUMN er_group_config.namespace_id IS '命名空间'; +COMMENT ON COLUMN er_group_config.group_name IS '组名称'; +COMMENT ON COLUMN er_group_config.description IS '组描述'; +COMMENT ON COLUMN er_group_config.token IS 'token'; +COMMENT ON COLUMN er_group_config.group_status IS '组状态 0、未启用 1、启用'; +COMMENT ON COLUMN er_group_config.version IS '版本号'; +COMMENT ON COLUMN er_group_config.group_partition IS '分区'; +COMMENT ON COLUMN er_group_config.id_generator_mode IS '唯一id生成模式 默认号段模式'; +COMMENT ON COLUMN er_group_config.init_scene IS '是否初始化场景 0:否 1:是'; +COMMENT ON COLUMN er_group_config.bucket_index IS 'bucket'; +COMMENT ON COLUMN er_group_config.create_dt IS '创建时间'; +COMMENT ON COLUMN er_group_config.update_dt IS '修改时间'; + +INSERT INTO er_group_config(namespace_id, group_name, description, token, group_status, version, group_partition, id_generator_mode, init_scene, bucket_index, create_dt, update_dt) VALUES ('dev', 'ruoyi_group', '', 'ER_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, 4, SYSDATE, SYSDATE ); + +-- er_notify_config +CREATE TABLE er_notify_config +( + id NUMBER GENERATED ALWAYS AS IDENTITY, + namespace_id VARCHAR2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR2(64) NOT NULL, + scene_name VARCHAR2(64) NOT NULL, + notify_status SMALLINT DEFAULT 0, + notify_type SMALLINT DEFAULT 0, + notify_attribute VARCHAR2(512) NOT NULL, + notify_threshold INT DEFAULT 0, + notify_scene SMALLINT DEFAULT 0, + rate_limiter_status SMALLINT DEFAULT 0, + rate_limiter_threshold INT DEFAULT 0, + description VARCHAR2(256) DEFAULT '', + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_notify_config_1 ON er_notify_config (namespace_id, group_name); + +COMMENT ON TABLE er_notify_config IS '通知配置'; +COMMENT ON COLUMN er_notify_config.id IS '主键'; +COMMENT ON COLUMN er_notify_config.group_name IS '组名称'; +COMMENT ON COLUMN er_notify_config.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_notify_config.scene_name IS '场景名称'; +COMMENT ON COLUMN er_notify_config.notify_status IS '通知状态 0、未启用 1、启用'; +COMMENT ON COLUMN er_notify_config.notify_type IS '通知类型 1、钉钉 2、邮件 3、企业微信'; +COMMENT ON COLUMN er_notify_config.notify_attribute IS '配置属性'; +COMMENT ON COLUMN er_notify_config.notify_threshold IS '通知阈值'; +COMMENT ON COLUMN er_notify_config.notify_scene IS '通知场景'; +COMMENT ON COLUMN er_notify_config.rate_limiter_status IS '限流状态 0、未启用 1、启用'; +COMMENT ON COLUMN er_notify_config.rate_limiter_threshold IS '每秒限流阈值'; +COMMENT ON COLUMN er_notify_config.description IS '描述'; +COMMENT ON COLUMN er_notify_config.create_dt IS '创建时间'; +COMMENT ON COLUMN er_notify_config.update_dt IS '修改时间'; + +-- er_retry_dead_letter +CREATE TABLE er_retry_dead_letter_0 +( + id NUMBER GENERATED ALWAYS AS IDENTITY, + unique_id VARCHAR2(64) NOT NULL, + namespace_id VARCHAR2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR2(64) NOT NULL, + scene_name VARCHAR2(64) NOT NULL, + idempotent_id VARCHAR2(64) NOT NULL, + biz_no VARCHAR2(64) DEFAULT '', + executor_name VARCHAR2(512) DEFAULT '', + args_str CLOB DEFAULT '', + ext_attrs CLOB DEFAULT '', + task_type SMALLINT DEFAULT 1, + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_retry_dead_letter_0_1 ON er_retry_dead_letter_0 (namespace_id, group_name, unique_id); +CREATE INDEX idx_retry_dead_letter_0_1 ON er_retry_dead_letter_0 (namespace_id, group_name, scene_name); +CREATE INDEX idx_retry_dead_letter_0_2 ON er_retry_dead_letter_0 (idempotent_id); +CREATE INDEX idx_retry_dead_letter_0_3 ON er_retry_dead_letter_0 (biz_no); +CREATE INDEX idx_retry_dead_letter_0_4 ON er_retry_dead_letter_0 (create_dt); + +COMMENT ON TABLE er_retry_dead_letter_0 IS '死信队列表'; +COMMENT ON COLUMN er_retry_dead_letter_0.id IS '主键'; +COMMENT ON COLUMN er_retry_dead_letter_0.unique_id IS '同组下id唯一'; +COMMENT ON COLUMN er_retry_dead_letter_0.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_retry_dead_letter_0.group_name IS '组名称'; +COMMENT ON COLUMN er_retry_dead_letter_0.scene_name IS '场景名称'; +COMMENT ON COLUMN er_retry_dead_letter_0.idempotent_id IS '幂等id'; +COMMENT ON COLUMN er_retry_dead_letter_0.biz_no IS '业务编号'; +COMMENT ON COLUMN er_retry_dead_letter_0.executor_name IS '执行器名称'; +COMMENT ON COLUMN er_retry_dead_letter_0.args_str IS '执行方法参数'; +COMMENT ON COLUMN er_retry_dead_letter_0.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN er_retry_dead_letter_0.task_type IS '任务类型 1、重试数据 2、回调数据'; +COMMENT ON COLUMN er_retry_dead_letter_0.create_dt IS '创建时间'; + +-- er_retry_task +CREATE TABLE er_retry_task_0 +( + id NUMBER GENERATED ALWAYS AS IDENTITY, + unique_id VARCHAR2(64) NOT NULL, + namespace_id VARCHAR2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR2(64) NOT NULL, + scene_name VARCHAR2(64) NOT NULL, + idempotent_id VARCHAR2(64) NOT NULL, + biz_no VARCHAR2(64) DEFAULT '', + executor_name VARCHAR2(512) DEFAULT '', + args_str CLOB DEFAULT '', + ext_attrs CLOB DEFAULT '', + next_trigger_at TIMESTAMP NOT NULL, + retry_count INT DEFAULT 0, + retry_status SMALLINT DEFAULT 0, + task_type SMALLINT DEFAULT 1, + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_retry_task_0_1 ON er_retry_task_0 (namespace_id, group_name, unique_id); +CREATE INDEX idx_retry_task_0_1 ON er_retry_task_0 (namespace_id, group_name, scene_name); +CREATE INDEX idx_retry_task_0_2 ON er_retry_task_0 (namespace_id, group_name, retry_status); +CREATE INDEX idx_retry_task_0_3 ON er_retry_task_0 (idempotent_id); +CREATE INDEX idx_retry_task_0_4 ON er_retry_task_0 (biz_no); +CREATE INDEX idx_retry_task_0_5 ON er_retry_task_0 (create_dt); + +COMMENT ON TABLE er_retry_task_0 IS '任务表'; +COMMENT ON COLUMN er_retry_task_0.id IS '主键'; +COMMENT ON COLUMN er_retry_task_0.unique_id IS '同组下id唯一'; +COMMENT ON COLUMN er_retry_task_0.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_retry_task_0.group_name IS '组名称'; +COMMENT ON COLUMN er_retry_task_0.scene_name IS '场景名称'; +COMMENT ON COLUMN er_retry_task_0.idempotent_id IS '幂等id'; +COMMENT ON COLUMN er_retry_task_0.biz_no IS '业务编号'; +COMMENT ON COLUMN er_retry_task_0.executor_name IS '执行器名称'; +COMMENT ON COLUMN er_retry_task_0.args_str IS '执行方法参数'; +COMMENT ON COLUMN er_retry_task_0.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN er_retry_task_0.next_trigger_at IS '下次触发时间'; +COMMENT ON COLUMN er_retry_task_0.retry_count IS '重试次数'; +COMMENT ON COLUMN er_retry_task_0.retry_status IS '重试状态 0、重试中 1、成功 2、最大重试次数'; +COMMENT ON COLUMN er_retry_task_0.task_type IS '任务类型 1、重试数据 2、回调数据'; +COMMENT ON COLUMN er_retry_task_0.create_dt IS '创建时间'; +COMMENT ON COLUMN er_retry_task_0.update_dt IS '修改时间'; + +-- er_retry_task_log +CREATE TABLE er_retry_task_log +( + id NUMBER GENERATED ALWAYS AS IDENTITY, + unique_id VARCHAR2(64) NOT NULL, + namespace_id VARCHAR2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR2(64) NOT NULL, + scene_name VARCHAR2(64) NOT NULL, + idempotent_id VARCHAR2(64) NOT NULL, + biz_no VARCHAR2(64) DEFAULT '', + executor_name VARCHAR2(512) DEFAULT '', + args_str CLOB DEFAULT '', + ext_attrs CLOB DEFAULT '', + retry_status SMALLINT DEFAULT 0, + task_type SMALLINT DEFAULT 1, + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_retry_task_log_1 ON er_retry_task_log (namespace_id, group_name, scene_name); +CREATE INDEX idx_retry_task_log_2 ON er_retry_task_log (retry_status); +CREATE INDEX idx_retry_task_log_3 ON er_retry_task_log (idempotent_id); +CREATE INDEX idx_retry_task_log_4 ON er_retry_task_log (namespace_id, group_name, unique_id); +CREATE INDEX idx_retry_task_log_5 ON er_retry_task_log (biz_no); +CREATE INDEX idx_retry_task_log_6 ON er_retry_task_log (create_dt); + +COMMENT ON TABLE er_retry_task_log IS '任务日志基础信息表'; +COMMENT ON COLUMN er_retry_task_log.id IS '主键'; +COMMENT ON COLUMN er_retry_task_log.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_retry_task_log.unique_id IS '同组下id唯一'; +COMMENT ON COLUMN er_retry_task_log.group_name IS '组名称'; +COMMENT ON COLUMN er_retry_task_log.scene_name IS '场景名称'; +COMMENT ON COLUMN er_retry_task_log.idempotent_id IS '幂等id'; +COMMENT ON COLUMN er_retry_task_log.biz_no IS '业务编号'; +COMMENT ON COLUMN er_retry_task_log.executor_name IS '执行器名称'; +COMMENT ON COLUMN er_retry_task_log.args_str IS '执行方法参数'; +COMMENT ON COLUMN er_retry_task_log.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN er_retry_task_log.retry_status IS '重试状态 0、重试中 1、成功 2、最大次数'; +COMMENT ON COLUMN er_retry_task_log.task_type IS '任务类型 1、重试数据 2、回调数据'; +COMMENT ON COLUMN er_retry_task_log.create_dt IS '创建时间'; +COMMENT ON COLUMN er_retry_task_log.update_dt IS '修改时间'; + +-- er_retry_task_log_message +CREATE TABLE er_retry_task_log_message +( + id NUMBER GENERATED ALWAYS AS IDENTITY, + namespace_id VARCHAR2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR2(64) NOT NULL, + unique_id VARCHAR2(64) NOT NULL, + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + message CLOB DEFAULT '', + log_num INT DEFAULT 1, + real_time NUMERIC(13) DEFAULT 0 +); + +CREATE INDEX idx_retry_task_log_message_1 ON er_retry_task_log_message (namespace_id, group_name, unique_id); +CREATE INDEX idx_retry_task_log_message_2 ON er_retry_task_log_message (create_dt); + +COMMENT ON TABLE er_retry_task_log_message IS '任务调度日志信息记录表'; +COMMENT ON COLUMN er_retry_task_log_message.id IS '主键'; +COMMENT ON COLUMN er_retry_task_log_message.namespace_id IS '命名空间'; +COMMENT ON COLUMN er_retry_task_log_message.group_name IS '组名称'; +COMMENT ON COLUMN er_retry_task_log_message.unique_id IS '同组下id唯一'; +COMMENT ON COLUMN er_retry_task_log_message.create_dt IS '创建时间'; +COMMENT ON COLUMN er_retry_task_log_message.message IS '异常信息'; +COMMENT ON COLUMN er_retry_task_log_message.log_num IS '日志数量'; +COMMENT ON COLUMN er_retry_task_log_message.real_time IS '上报时间'; + +-- er_scene_config +CREATE TABLE er_scene_config +( + id NUMBER GENERATED ALWAYS AS IDENTITY, + namespace_id VARCHAR2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + scene_name VARCHAR2(64) NOT NULL, + group_name VARCHAR2(64) NOT NULL, + scene_status SMALLINT DEFAULT 0, + max_retry_count INT DEFAULT 5, + back_off SMALLINT DEFAULT 1, + trigger_interval VARCHAR2(16) DEFAULT '', + deadline_request NUMBER(20) DEFAULT 60000, + route_key SMALLINT DEFAULT 4, + executor_timeout INT DEFAULT 5, + description VARCHAR2(256) DEFAULT '', + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_scene_config_1 ON er_scene_config (namespace_id, group_name, scene_name); + +COMMENT ON TABLE er_scene_config IS '场景配置'; +COMMENT ON COLUMN er_scene_config.id IS '主键'; +COMMENT ON COLUMN er_scene_config.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_scene_config.scene_name IS '场景名称'; +COMMENT ON COLUMN er_scene_config.group_name IS '组名称'; +COMMENT ON COLUMN er_scene_config.scene_status IS '组状态 0、未启用 1、启用'; +COMMENT ON COLUMN er_scene_config.max_retry_count IS '最大重试次数'; +COMMENT ON COLUMN er_scene_config.back_off IS '1、默认等级 2、固定间隔时间 3、CRON 表达式'; +COMMENT ON COLUMN er_scene_config.trigger_interval IS '间隔时长'; +COMMENT ON COLUMN er_scene_config.deadline_request IS 'Deadline Request 调用链超时 单位毫秒'; +COMMENT ON COLUMN er_scene_config.description IS '描述'; +COMMENT ON COLUMN er_scene_config.route_key IS '路由策略'; +COMMENT ON COLUMN er_scene_config.executor_timeout IS '超时时间'; +COMMENT ON COLUMN er_scene_config.create_dt IS '创建时间'; +COMMENT ON COLUMN er_scene_config.update_dt IS '修改时间'; + +-- er_server_node +CREATE TABLE er_server_node +( + id NUMBER GENERATED ALWAYS AS IDENTITY, + namespace_id VARCHAR2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR2(64) NOT NULL, + host_id VARCHAR2(64) NOT NULL, + host_ip VARCHAR2(64) NOT NULL, + context_path VARCHAR2(256) DEFAULT '/', + host_port INT NOT NULL, + expire_at TIMESTAMP NOT NULL, + node_type SMALLINT NOT NULL, + ext_attrs VARCHAR2(256) DEFAULT '', + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_server_node_1 ON er_server_node (host_id, host_ip); +CREATE INDEX idx_server_node_1 ON er_server_node (expire_at, node_type); +CREATE INDEX idx_server_node_2 ON er_server_node (namespace_id, group_name); + +COMMENT ON TABLE er_server_node IS '服务器节点'; +COMMENT ON COLUMN er_server_node.id IS '主键'; +COMMENT ON COLUMN er_server_node.group_name IS '组名称'; +COMMENT ON COLUMN er_server_node.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_server_node.host_id IS '主机id'; +COMMENT ON COLUMN er_server_node.host_ip IS '机器ip'; +COMMENT ON COLUMN er_server_node.context_path IS '客户端上下文路径 server.servlet.context-path'; +COMMENT ON COLUMN er_server_node.host_port IS '机器端口'; +COMMENT ON COLUMN er_server_node.expire_at IS '过期时间'; +COMMENT ON COLUMN er_server_node.node_type IS '节点类型 1、客户端 2、是服务端'; +COMMENT ON COLUMN er_server_node.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN er_server_node.create_dt IS '创建时间'; +COMMENT ON COLUMN er_server_node.update_dt IS '修改时间'; + +-- er_distributed_lock +CREATE TABLE er_distributed_lock +( + id NUMBER GENERATED ALWAYS AS IDENTITY, + name VARCHAR2(64) NOT NULL, + lock_until TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + locked_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + locked_by VARCHAR2(255) NOT NULL, + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +ALTER TABLE er_distributed_lock + ADD CONSTRAINT uk_name_distributed_lock UNIQUE (name); + +COMMENT ON TABLE er_distributed_lock IS '锁定表'; +COMMENT ON COLUMN er_distributed_lock.id IS '主键'; +COMMENT ON COLUMN er_distributed_lock.name IS '锁名称'; +COMMENT ON COLUMN er_distributed_lock.lock_until IS '锁定时长'; +COMMENT ON COLUMN er_distributed_lock.locked_at IS '锁定时间'; +COMMENT ON COLUMN er_distributed_lock.locked_by IS '锁定者'; +COMMENT ON COLUMN er_distributed_lock.create_dt IS '创建时间'; +COMMENT ON COLUMN er_distributed_lock.update_dt IS '修改时间'; + +-- er_system_user +CREATE TABLE er_system_user +( + id NUMBER GENERATED ALWAYS AS IDENTITY, + username VARCHAR2(64) NOT NULL, + password VARCHAR2(128) NOT NULL, + role SMALLINT DEFAULT 0, + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_system_user_1 ON er_system_user (username); + +COMMENT ON TABLE er_system_user IS '系统用户表'; +COMMENT ON COLUMN er_system_user.id IS '主键'; +COMMENT ON COLUMN er_system_user.username IS '账号'; +COMMENT ON COLUMN er_system_user.password IS '密码'; +COMMENT ON COLUMN er_system_user.role IS '角色:1-普通用户、2-管理员'; +COMMENT ON COLUMN er_system_user.create_dt IS '创建时间'; +COMMENT ON COLUMN er_system_user.update_dt IS '修改时间'; + +-- pwd: admin +INSERT INTO er_system_user(username, password, role, create_dt, update_dt) VALUES ('admin', '465c194afb65670f38322df087f0a9bb225cc257e43eb4ac5a0c98ef5b3173ac', 2, SYSDATE, SYSDATE); + +-- er_system_user_permission +CREATE TABLE er_system_user_permission +( + id NUMBER GENERATED ALWAYS AS IDENTITY, + namespace_id VARCHAR2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR2(64) NOT NULL, + system_user_id NUMBER(20) NOT NULL, + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_system_user_permission_1 ON er_system_user_permission (namespace_id, group_name, system_user_id); + +COMMENT ON TABLE er_system_user_permission IS '系统用户权限表'; +COMMENT ON COLUMN er_system_user_permission.id IS '主键'; +COMMENT ON COLUMN er_system_user_permission.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_system_user_permission.group_name IS '组名称'; +COMMENT ON COLUMN er_system_user_permission.system_user_id IS '系统用户id'; +COMMENT ON COLUMN er_system_user_permission.create_dt IS '创建时间'; +COMMENT ON COLUMN er_system_user_permission.update_dt IS '修改时间'; + +-- er_sequence_alloc +CREATE TABLE er_sequence_alloc +( + id NUMBER GENERATED ALWAYS AS IDENTITY, + namespace_id VARCHAR2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR2(64) DEFAULT '', + max_id NUMBER(20) DEFAULT 1, + step INT DEFAULT 100, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_sequence_alloc_1 ON er_sequence_alloc (namespace_id, group_name); + +COMMENT ON TABLE er_sequence_alloc IS '号段模式序号ID分配表'; +COMMENT ON COLUMN er_sequence_alloc.id IS '主键'; +COMMENT ON COLUMN er_sequence_alloc.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_sequence_alloc.group_name IS '组名称'; +COMMENT ON COLUMN er_sequence_alloc.max_id IS '最大id'; +COMMENT ON COLUMN er_sequence_alloc.step IS '步长'; +COMMENT ON COLUMN er_sequence_alloc.update_dt IS '更新时间'; + +-- er_job +CREATE TABLE er_job +( + id NUMBER GENERATED ALWAYS AS IDENTITY, + namespace_id VARCHAR2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR2(64) NOT NULL, + job_name VARCHAR2(64) NOT NULL, + args_str CLOB DEFAULT '', + args_type SMALLINT DEFAULT 1, + next_trigger_at NUMBER(20) NOT NULL, + job_status SMALLINT DEFAULT 1, + task_type SMALLINT DEFAULT 1, + route_key SMALLINT DEFAULT 4, + executor_type SMALLINT DEFAULT 1, + executor_info VARCHAR2(255) DEFAULT NULL, + trigger_type SMALLINT NOT NULL, + trigger_interval VARCHAR2(255) NOT NULL, + block_strategy SMALLINT DEFAULT 1, + executor_timeout INT DEFAULT 0, + max_retry_times INT DEFAULT 0, + parallel_num INT DEFAULT 1, + retry_interval INT DEFAULT 0, + bucket_index INT DEFAULT 0, + resident SMALLINT DEFAULT 0, + description VARCHAR2(256) DEFAULT '', + ext_attrs VARCHAR2(256) DEFAULT '', + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + deleted SMALLINT DEFAULT 0 +); + +CREATE INDEX idx_job_1 ON er_job (namespace_id, group_name); +CREATE INDEX idx_job_2 ON er_job (job_status, bucket_index); +CREATE INDEX idx_job_3 ON er_job (create_dt); + +COMMENT ON TABLE er_job IS '任务信息'; +COMMENT ON COLUMN er_job.id IS '主键'; +COMMENT ON COLUMN er_job.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_job.group_name IS '组名称'; +COMMENT ON COLUMN er_job.job_name IS '名称'; +COMMENT ON COLUMN er_job.args_str IS '执行方法参数'; +COMMENT ON COLUMN er_job.args_type IS '参数类型'; +COMMENT ON COLUMN er_job.next_trigger_at IS '下次触发时间'; +COMMENT ON COLUMN er_job.job_status IS '重试状态 0、关闭、1、开启'; +COMMENT ON COLUMN er_job.task_type IS '任务类型 1、集群 2、广播 3、切片'; +COMMENT ON COLUMN er_job.route_key IS '路由策略'; +COMMENT ON COLUMN er_job.executor_type IS '执行器类型'; +COMMENT ON COLUMN er_job.executor_info IS '执行器名称'; +COMMENT ON COLUMN er_job.trigger_type IS '触发类型 1.CRON 表达式 2. 固定时间'; +COMMENT ON COLUMN er_job.trigger_interval IS '间隔时长'; +COMMENT ON COLUMN er_job.block_strategy IS '阻塞策略 1、丢弃 2、覆盖 3、并行'; +COMMENT ON COLUMN er_job.executor_timeout IS '任务执行超时时间,单位秒'; +COMMENT ON COLUMN er_job.max_retry_times IS '最大重试次数'; +COMMENT ON COLUMN er_job.parallel_num IS '并行数'; +COMMENT ON COLUMN er_job.retry_interval IS '更新重试间隔(s)'; +COMMENT ON COLUMN er_job.bucket_index IS 'bucket'; +COMMENT ON COLUMN er_job.resident IS '是否是常驻任务'; +COMMENT ON COLUMN er_job.description IS '描述'; +COMMENT ON COLUMN er_job.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN er_job.create_dt IS '创建时间'; +COMMENT ON COLUMN er_job.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN er_job.update_dt IS '更新时间'; + +-- er_job_log_message +CREATE TABLE er_job_log_message +( + id NUMBER GENERATED ALWAYS AS IDENTITY, + namespace_id VARCHAR2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR2(64) NOT NULL, + job_id NUMBER(20) NOT NULL, + task_batch_id NUMBER(20) NOT NULL, + task_id NUMBER(20) NOT NULL, + message CLOB DEFAULT '', + log_num INT DEFAULT 1, + real_time NUMBER(20) DEFAULT 0, + ext_attrs VARCHAR2(256) DEFAULT '', + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_job_log_message_1 ON er_job_log_message (namespace_id, group_name); +CREATE INDEX idx_job_log_message_2 ON er_job_log_message (task_batch_id, task_id); +CREATE INDEX idx_job_log_message_3 ON er_job_log_message (create_dt); + +COMMENT ON TABLE er_job_log_message IS '调度日志'; +COMMENT ON COLUMN er_job_log_message.id IS '主键'; +COMMENT ON COLUMN er_job_log_message.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_job_log_message.group_name IS '组名称'; +COMMENT ON COLUMN er_job_log_message.job_id IS '任务信息id'; +COMMENT ON COLUMN er_job_log_message.task_batch_id IS '任务批次id'; +COMMENT ON COLUMN er_job_log_message.task_id IS '调度任务id'; +COMMENT ON COLUMN er_job_log_message.message IS '调度信息'; +COMMENT ON COLUMN er_job_log_message.log_num IS '日志序号'; +COMMENT ON COLUMN er_job_log_message.real_time IS '实际时间'; +COMMENT ON COLUMN er_job_log_message.create_dt IS '创建时间'; +COMMENT ON COLUMN er_job_log_message.ext_attrs IS '扩展字段'; + +-- er_job_task +CREATE TABLE er_job_task +( + id NUMBER GENERATED ALWAYS AS IDENTITY, + namespace_id VARCHAR2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR2(64) NOT NULL, + job_id NUMBER(20) NOT NULL, + task_batch_id NUMBER(20) NOT NULL, + parent_id NUMBER(20) DEFAULT 0, + task_status SMALLINT DEFAULT 0, + retry_count INT DEFAULT 0, + client_info VARCHAR2(128) DEFAULT NULL, + result_message CLOB DEFAULT '', + args_str CLOB DEFAULT '', + args_type SMALLINT DEFAULT 1, + ext_attrs VARCHAR2(256) DEFAULT '', + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_job_task_1 ON er_job_task (namespace_id, group_name); +CREATE INDEX idx_job_task_2 ON er_job_task (task_batch_id, task_status); +CREATE INDEX idx_job_task_3 ON er_job_task (create_dt); + +COMMENT ON TABLE er_job_task IS '任务实例'; +COMMENT ON COLUMN er_job_task.id IS '主键'; +COMMENT ON COLUMN er_job_task.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_job_task.group_name IS '组名称'; +COMMENT ON COLUMN er_job_task.job_id IS '任务信息id'; +COMMENT ON COLUMN er_job_task.task_batch_id IS '任务批次id'; +COMMENT ON COLUMN er_job_task.parent_id IS '父执行器id'; +COMMENT ON COLUMN er_job_task.task_status IS '执行的状态 0、失败 1、成功'; +COMMENT ON COLUMN er_job_task.retry_count IS '重试次数'; +COMMENT ON COLUMN er_job_task.client_info IS '客户端地址 clientId#ip:port'; +COMMENT ON COLUMN er_job_task.result_message IS '调度信息'; +COMMENT ON COLUMN er_job_task.args_str IS '执行方法参数'; +COMMENT ON COLUMN er_job_task.args_type IS '参数类型'; +COMMENT ON COLUMN er_job_task.create_dt IS '创建时间'; +COMMENT ON COLUMN er_job_task.update_dt IS '创建时间'; +COMMENT ON COLUMN er_job_task.ext_attrs IS '扩展字段'; + +-- er_job_task_batch +CREATE TABLE er_job_task_batch +( + id NUMBER GENERATED ALWAYS AS IDENTITY, + namespace_id VARCHAR2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR2(64) NOT NULL, + job_id NUMBER(20) NOT NULL, + workflow_node_id NUMBER(20) DEFAULT 0, + parent_workflow_node_id NUMBER(20) DEFAULT 0, + workflow_task_batch_id NUMBER(20) DEFAULT 0, + parent_id VARCHAR2(64) DEFAULT '', + task_batch_status SMALLINT DEFAULT 0, + operation_reason SMALLINT DEFAULT 0, + execution_at NUMBER(20) DEFAULT 0, + system_task_type SMALLINT DEFAULT 3, + ext_attrs VARCHAR2(256) DEFAULT '', + deleted SMALLINT DEFAULT 0, + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_job_task_batch_1 ON er_job_task_batch (namespace_id, group_name); +CREATE INDEX idx_job_task_batch_2 ON er_job_task_batch (job_id, task_batch_status); +CREATE INDEX idx_job_task_batch_3 ON er_job_task_batch (create_dt); +CREATE INDEX idx_job_task_batch_4 ON er_job_task_batch (workflow_task_batch_id, workflow_node_id); + +COMMENT ON TABLE er_job_task_batch IS '任务批次'; +COMMENT ON COLUMN er_job_task_batch.id IS '主键'; +COMMENT ON COLUMN er_job_task_batch.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_job_task_batch.group_name IS '组名称'; +COMMENT ON COLUMN er_job_task_batch.job_id IS '任务信息id'; +COMMENT ON COLUMN er_job_task_batch.task_batch_status IS '任务批次状态 0、失败 1、成功'; +COMMENT ON COLUMN er_job_task_batch.operation_reason IS '操作原因'; +COMMENT ON COLUMN er_job_task_batch.workflow_node_id IS '工作流节点id'; +COMMENT ON COLUMN er_job_task_batch.parent_workflow_node_id IS '父节点'; +COMMENT ON COLUMN er_job_task_batch.workflow_task_batch_id IS '任务批次id'; +COMMENT ON COLUMN er_job_task_batch.system_task_type IS '任务类型 0、系统任务 1、业务任务'; +COMMENT ON COLUMN er_job_task_batch.execution_at IS '任务执行时间'; +COMMENT ON COLUMN er_job_task_batch.parent_id IS '父节点'; +COMMENT ON COLUMN er_job_task_batch.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN er_job_task_batch.create_dt IS '创建时间'; +COMMENT ON COLUMN er_job_task_batch.update_dt IS '创建时间'; +COMMENT ON COLUMN er_job_task_batch.ext_attrs IS '扩展字段'; + +CREATE TABLE er_job_notify_config +( + id NUMBER GENERATED ALWAYS AS IDENTITY, + namespace_id VARCHAR2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR2(64) NOT NULL, + job_id NUMBER(20) NOT NULL, + notify_status SMALLINT DEFAULT 0, + notify_type SMALLINT DEFAULT 0, + notify_attribute VARCHAR2(512) NOT NULL, + notify_threshold INT DEFAULT 0, + notify_scene SMALLINT DEFAULT 0, + rate_limiter_status SMALLINT DEFAULT 0, + rate_limiter_threshold INT DEFAULT 0, + description VARCHAR2(256) DEFAULT '', + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_job_notify_config_1 ON er_job_notify_config (namespace_id, group_name, job_id); + +COMMENT ON TABLE er_job_notify_config IS '通知配置'; +COMMENT ON COLUMN er_job_notify_config.id IS '主键'; +COMMENT ON COLUMN er_job_notify_config.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_job_notify_config.group_name IS '组名称'; +COMMENT ON COLUMN er_job_notify_config.job_id IS '任务信息id'; +COMMENT ON COLUMN er_job_notify_config.notify_status IS '通知状态 0、未启用 1、启用'; +COMMENT ON COLUMN er_job_notify_config.notify_type IS '通知类型 1、钉钉 2、邮件 3、企业微信'; +COMMENT ON COLUMN er_job_notify_config.notify_attribute IS '配置属性'; +COMMENT ON COLUMN er_job_notify_config.notify_threshold IS '通知阈值'; +COMMENT ON COLUMN er_job_notify_config.notify_scene IS '通知场景'; +COMMENT ON COLUMN er_job_notify_config.rate_limiter_status IS '限流状态 0、未启用 1、启用'; +COMMENT ON COLUMN er_job_notify_config.rate_limiter_threshold IS '每秒限流阈值'; +COMMENT ON COLUMN er_job_notify_config.description IS '描述'; +COMMENT ON COLUMN er_job_notify_config.create_dt IS '创建时间'; +COMMENT ON COLUMN er_job_notify_config.update_dt IS '修改时间'; + +-- er_retry_summary +CREATE TABLE er_retry_summary +( + id NUMBER GENERATED ALWAYS AS IDENTITY, + namespace_id VARCHAR2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR2(64) DEFAULT '', + scene_name VARCHAR2(50) DEFAULT '', + trigger_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + running_num INT DEFAULT 0, + finish_num INT DEFAULT 0, + max_count_num INT DEFAULT 0, + suspend_num INT DEFAULT 0, + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_retry_summary_1 ON er_retry_summary (namespace_id, group_name, scene_name, trigger_at); + +COMMENT ON TABLE er_retry_summary IS 'DashBoard_Retry'; +COMMENT ON COLUMN er_retry_summary.id IS '主键'; +COMMENT ON COLUMN er_retry_summary.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_retry_summary.group_name IS '组名称'; +COMMENT ON COLUMN er_retry_summary.scene_name IS '场景名称'; +COMMENT ON COLUMN er_retry_summary.trigger_at IS '统计时间'; +COMMENT ON COLUMN er_retry_summary.running_num IS '重试中-日志数量'; +COMMENT ON COLUMN er_retry_summary.finish_num IS '重试完成-日志数量'; +COMMENT ON COLUMN er_retry_summary.max_count_num IS '重试到达最大次数-日志数量'; +COMMENT ON COLUMN er_retry_summary.suspend_num IS '暂停重试-日志数量'; +COMMENT ON COLUMN er_retry_summary.create_dt IS '创建时间'; +COMMENT ON COLUMN er_retry_summary.update_dt IS '修改时间'; + +-- er_job_summary +CREATE TABLE er_job_summary +( + id NUMBER GENERATED ALWAYS AS IDENTITY, + namespace_id VARCHAR2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR2(64) DEFAULT '', + business_id NUMBER(20) NOT NULL, + system_task_type SMALLINT DEFAULT '3', + trigger_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + success_num INT DEFAULT 0, + fail_num INT DEFAULT 0, + fail_reason VARCHAR2(512) DEFAULT '', + stop_num INT DEFAULT 0, + stop_reason VARCHAR2(512) DEFAULT '', + cancel_num INT DEFAULT 0, + cancel_reason VARCHAR2(512) DEFAULT '', + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_job_summary_1 ON er_job_summary (trigger_at, system_task_type, business_id); +CREATE INDEX idx_job_summary_1 ON er_job_summary (namespace_id, group_name, business_id); + +COMMENT ON TABLE er_job_summary IS 'DashBoard_Job'; +COMMENT ON COLUMN er_job_summary.id IS '主键'; +COMMENT ON COLUMN er_job_summary.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_job_summary.group_name IS '组名称'; +COMMENT ON COLUMN er_job_summary.business_id IS '业务id (job_id或workflow_id)'; +COMMENT ON COLUMN er_job_summary.system_task_type IS '任务类型 3、JOB任务 4、WORKFLOW任务'; +COMMENT ON COLUMN er_job_summary.trigger_at IS '统计时间'; +COMMENT ON COLUMN er_job_summary.success_num IS '执行成功-日志数量'; +COMMENT ON COLUMN er_job_summary.fail_num IS '执行失败-日志数量'; +COMMENT ON COLUMN er_job_summary.fail_reason IS '失败原因'; +COMMENT ON COLUMN er_job_summary.stop_num IS '执行失败-日志数量'; +COMMENT ON COLUMN er_job_summary.stop_reason IS '失败原因'; +COMMENT ON COLUMN er_job_summary.cancel_num IS '执行失败-日志数量'; +COMMENT ON COLUMN er_job_summary.cancel_reason IS '失败原因'; + +-- er_workflow +CREATE TABLE er_workflow +( + id NUMBER GENERATED ALWAYS AS IDENTITY, + workflow_name VARCHAR2(64) NOT NULL, + namespace_id VARCHAR2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR2(64) NOT NULL, + workflow_status SMALLINT DEFAULT 1, + trigger_type SMALLINT NOT NULL, + trigger_interval VARCHAR2(255) NOT NULL, + next_trigger_at NUMBER(20) NOT NULL, + block_strategy SMALLINT DEFAULT 1, + executor_timeout INT DEFAULT 0, + description VARCHAR2(256) DEFAULT '', + flow_info CLOB DEFAULT '', + bucket_index INT DEFAULT 0, + version INT NOT NULL, + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + deleted SMALLINT DEFAULT 0, + ext_attrs VARCHAR2(256) DEFAULT '' +); + +CREATE INDEX idx_workflow_1 ON er_workflow (create_dt); +CREATE INDEX idx_workflow_2 ON er_workflow (namespace_id, group_name); + +COMMENT ON TABLE er_workflow IS '工作流'; +COMMENT ON COLUMN er_workflow.id IS '主键'; +COMMENT ON COLUMN er_workflow.workflow_name IS '工作流名称'; +COMMENT ON COLUMN er_workflow.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_workflow.group_name IS '组名称'; +COMMENT ON COLUMN er_workflow.workflow_status IS '工作流状态 0、关闭、1、开启'; +COMMENT ON COLUMN er_workflow.trigger_type IS '触发类型 1.CRON 表达式 2. 固定时间'; +COMMENT ON COLUMN er_workflow.trigger_interval IS '间隔时长'; +COMMENT ON COLUMN er_workflow.next_trigger_at IS '下次触发时间'; +COMMENT ON COLUMN er_workflow.block_strategy IS '阻塞策略 1、丢弃 2、覆盖 3、并行'; +COMMENT ON COLUMN er_workflow.executor_timeout IS '任务执行超时时间,单位秒'; +COMMENT ON COLUMN er_workflow.description IS '描述'; +COMMENT ON COLUMN er_workflow.flow_info IS '流程信息'; +COMMENT ON COLUMN er_workflow.bucket_index IS 'bucket'; +COMMENT ON COLUMN er_workflow.version IS '版本号'; +COMMENT ON COLUMN er_workflow.create_dt IS '创建时间'; +COMMENT ON COLUMN er_workflow.update_dt IS '修改时间'; +COMMENT ON COLUMN er_workflow.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN er_workflow.ext_attrs IS '扩展字段'; + +-- er_workflow_node +CREATE TABLE er_workflow_node +( + id NUMBER GENERATED ALWAYS AS IDENTITY, + namespace_id VARCHAR2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + node_name VARCHAR2(64) NOT NULL, + group_name VARCHAR2(64) NOT NULL, + job_id NUMBER(20) NOT NULL, + workflow_id NUMBER(20) NOT NULL, + node_type SMALLINT DEFAULT 1, + expression_type SMALLINT DEFAULT 0, + fail_strategy SMALLINT DEFAULT 1, + workflow_node_status SMALLINT DEFAULT 1, + priority_level INT DEFAULT 1, + node_info CLOB DEFAULT '', + version INT NOT NULL, + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + deleted SMALLINT DEFAULT 0, + ext_attrs VARCHAR2(256) DEFAULT '' +); + +CREATE INDEX idx_workflow_node_1 ON er_workflow_node (create_dt); +CREATE INDEX idx_workflow_node_2 ON er_workflow_node (namespace_id, group_name); + +COMMENT ON TABLE er_workflow_node IS '工作流节点'; +COMMENT ON COLUMN er_workflow_node.id IS '主键'; +COMMENT ON COLUMN er_workflow_node.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_workflow_node.node_name IS '节点名称'; +COMMENT ON COLUMN er_workflow_node.group_name IS '组名称'; +COMMENT ON COLUMN er_workflow_node.job_id IS '任务信息id'; +COMMENT ON COLUMN er_workflow_node.workflow_id IS '工作流ID'; +COMMENT ON COLUMN er_workflow_node.node_type IS '1、任务节点 2、条件节点'; +COMMENT ON COLUMN er_workflow_node.expression_type IS '1、SpEl、2、Aviator 3、QL'; +COMMENT ON COLUMN er_workflow_node.fail_strategy IS '失败策略 1、跳过 2、阻塞'; +COMMENT ON COLUMN er_workflow_node.workflow_node_status IS '工作流节点状态 0、关闭、1、开启'; +COMMENT ON COLUMN er_workflow_node.priority_level IS '优先级'; +COMMENT ON COLUMN er_workflow_node.node_info IS '节点信息'; +COMMENT ON COLUMN er_workflow_node.version IS '版本号'; +COMMENT ON COLUMN er_workflow_node.create_dt IS '创建时间'; +COMMENT ON COLUMN er_workflow_node.update_dt IS '修改时间'; +COMMENT ON COLUMN er_workflow_node.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN er_workflow_node.ext_attrs IS '扩展字段'; + +-- er_workflow_task_batch +CREATE TABLE er_workflow_task_batch +( + id NUMBER GENERATED ALWAYS AS IDENTITY, + namespace_id VARCHAR2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR2(64) NOT NULL, + workflow_id NUMBER(20) NOT NULL, + task_batch_status SMALLINT DEFAULT 0, + operation_reason SMALLINT DEFAULT 0, + flow_info CLOB DEFAULT '', + execution_at NUMBER(20) DEFAULT 0, + create_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + deleted SMALLINT DEFAULT 0, + ext_attrs VARCHAR2(256) DEFAULT '' +); + +CREATE INDEX idx_workflow_task_batch_1 ON er_workflow_task_batch (workflow_id, task_batch_status); +CREATE INDEX idx_workflow_task_batch_2 ON er_workflow_task_batch (create_dt); +CREATE INDEX idx_workflow_task_batch_3 ON er_workflow_task_batch (namespace_id, group_name); + +COMMENT ON TABLE er_workflow_task_batch IS '工作流批次'; +COMMENT ON COLUMN er_workflow_task_batch.id IS '主键'; +COMMENT ON COLUMN er_workflow_task_batch.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_workflow_task_batch.group_name IS '组名称'; +COMMENT ON COLUMN er_workflow_task_batch.workflow_id IS '工作流任务id'; +COMMENT ON COLUMN er_workflow_task_batch.task_batch_status IS '任务批次状态 0、失败 1、成功'; +COMMENT ON COLUMN er_workflow_task_batch.operation_reason IS '操作原因'; +COMMENT ON COLUMN er_workflow_task_batch.flow_info IS '流程信息'; +COMMENT ON COLUMN er_workflow_task_batch.execution_at IS '任务执行时间'; +COMMENT ON COLUMN er_workflow_task_batch.create_dt IS '创建时间'; +COMMENT ON COLUMN er_workflow_task_batch.update_dt IS '修改时间'; +COMMENT ON COLUMN er_workflow_task_batch.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN er_workflow_task_batch.ext_attrs IS '扩展字段'; diff --git a/script/sql/oracle/flowable.sql b/script/sql/oracle/flowable.sql new file mode 100644 index 000000000..52d547e99 --- /dev/null +++ b/script/sql/oracle/flowable.sql @@ -0,0 +1,260 @@ +insert into sys_menu values('11616', '工作流' , '0', '6', 'workflow', '', '', '1', '0', 'M', '0', '0', '', 'tree-table', 103, 1, sysdate, NULL, NULL, ''); +insert into sys_menu values('11617', '模型管理', '11616', '2', 'model', 'workflow/model/index', '', '1', '1', 'C', '0', '0', 'workflow:model:list', 'tree-table', 103, 1, sysdate, NULL, NULL, ''); +insert into sys_menu values('11618', '我的任务', '0', '7', 'task', '', '', '1', '0', 'M', '0', '0', '', 'tree-table', 103, 1, sysdate, NULL, NULL, ''); +insert into sys_menu values('11619', '我的待办', '11618', '2', 'taskWaiting', 'workflow/task/taskWaiting', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, sysdate, NULL, NULL, ''); +insert into sys_menu values('11632', '我的已办', '11618', '3', 'taskFinish', 'workflow/task/taskFinish', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, sysdate, NULL, NULL, ''); +insert into sys_menu values('11633', '我的抄送', '11618', '4', 'taskCopyList', 'workflow/task/taskCopyList', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, sysdate, NULL, NULL, ''); +insert into sys_menu values('11620', '流程定义', '11616', '3', 'processDefinition', 'workflow/processDefinition/index', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, sysdate, NULL, NULL, ''); +insert into sys_menu values('11621', '流程实例', '11630', '1', 'processInstance', 'workflow/processInstance/index', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, sysdate, NULL, NULL, ''); +insert into sys_menu values('11622', '流程分类', '11616', '1', 'category', 'workflow/category/index', '', '1', '0', 'C', '0', '0', 'workflow:category:list', 'tree-table', 103, 1, sysdate, NULL, NULL, ''); +insert into sys_menu values('11629', '我发起的', '11618', '1', 'myDocument', 'workflow/task/myDocument', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, sysdate, NULL, NULL, ''); +insert into sys_menu values('11630', '流程监控', '11616', '4', 'monitor', '', '', '1', '0', 'M', '0', '0', '', 'tree-table', 103, 1, sysdate, NULL, NULL, ''); +insert into sys_menu values('11631', '待办任务', '11630', '2', 'allTaskWaiting', 'workflow/task/allTaskWaiting', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, sysdate, NULL, NULL, ''); + + +-- 流程分类管理相关按钮 +insert into sys_menu values ('11623', '流程分类查询', '11622', '1', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values ('11624', '流程分类新增', '11622', '2', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values ('11625', '流程分类修改', '11622', '3', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values ('11626', '流程分类删除', '11622', '4', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:remove','#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values ('11627', '流程分类导出', '11622', '5', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:export','#', 103, 1, sysdate, null, null, ''); + +-- 请假单信息 +create table TEST_LEAVE +( + ID NUMBER(20) not null + constraint PK_TEST_LEAVE + primary key, + LEAVE_TYPE VARCHAR2(255), + START_DATE DATE, + END_DATE DATE, + LEAVE_DAYS NUMBER(10), + REMARK VARCHAR2(255), + CREATE_DEPT NUMBER(20), + CREATE_BY NUMBER(20), + CREATE_TIME DATE, + UPDATE_BY NUMBER(20), + UPDATE_TIME DATE, + TENANT_ID VARCHAR2(20) +); + +comment on table TEST_LEAVE is '请假申请表' +comment on column TEST_LEAVE.ID is '主键' +comment on column TEST_LEAVE.LEAVE_TYPE is '请假类型' +comment on column TEST_LEAVE.START_DATE is '开始时间' +comment on column TEST_LEAVE.END_DATE is '结束时间' +comment on column TEST_LEAVE.LEAVE_DAYS is '请假天数' +comment on column TEST_LEAVE.REMARK is '请假原因' +comment on column TEST_LEAVE.CREATE_DEPT is '创建部门' +comment on column TEST_LEAVE.CREATE_BY is '创建者' +comment on column TEST_LEAVE.CREATE_TIME is '创建时间' +comment on column TEST_LEAVE.UPDATE_BY is '更新者' +comment on column TEST_LEAVE.UPDATE_TIME is '更新时间' +comment on column TEST_LEAVE.TENANT_ID is '租户编号' + +-- 流程分类信息表 +create table WF_CATEGORY +( + ID NUMBER(20) not null + constraint PK_WF_CATEGORY + primary key, + CATEGORY_NAME VARCHAR2(255), + CATEGORY_CODE VARCHAR2(255) + constraint UNI_CATEGORY_CODE + unique, + PARENT_ID NUMBER(20), + SORT_NUM NUMBER(10), + TENANT_ID VARCHAR2(20), + CREATE_DEPT NUMBER(20), + CREATE_BY NUMBER(20), + CREATE_TIME DATE, + UPDATE_BY NUMBER(20), + UPDATE_TIME DATE +); + +comment on table WF_CATEGORY is '流程分类' +comment on column WF_CATEGORY.ID is '主键' +comment on column WF_CATEGORY.CATEGORY_NAME is '分类名称' +comment on column WF_CATEGORY.CATEGORY_CODE is '分类编码' +comment on column WF_CATEGORY.PARENT_ID is '父级id' +comment on column WF_CATEGORY.SORT_NUM is '排序' +comment on column WF_CATEGORY.TENANT_ID is '租户编号' +comment on column WF_CATEGORY.CREATE_DEPT is '创建部门' +comment on column WF_CATEGORY.CREATE_BY is '创建者' +comment on column WF_CATEGORY.CREATE_TIME is '创建时间' +comment on column WF_CATEGORY.UPDATE_BY is '更新者' +comment on column WF_CATEGORY.UPDATE_TIME is '更新时间' +INSERT INTO wf_category values (1, 'OA', 'OA', 0, 0, '000000', 103, 1, sysdate, 1, sysdate); + +create table WF_TASK_BACK_NODE +( + ID NUMBER(20) not null + constraint PK_WF_TASK_BACK_NODE + primary key, + NODE_ID VARCHAR2(255) not null, + NODE_NAME VARCHAR2(255) not null, + ORDER_NO NUMBER(20) not null, + INSTANCE_ID VARCHAR2(255) not null, + TASK_TYPE VARCHAR2(255) not null, + ASSIGNEE VARCHAR2(2000) not null, + TENANT_ID VARCHAR2(20), + CREATE_DEPT NUMBER(20), + CREATE_BY NUMBER(20), + CREATE_TIME DATE, + UPDATE_BY NUMBER(20), + UPDATE_TIME DATE +); +comment on table WF_TASK_BACK_NODE is '节点审批记录' +comment on column WF_TASK_BACK_NODE.ID is '主键' +comment on column WF_TASK_BACK_NODE.NODE_ID is '节点id' +comment on column WF_TASK_BACK_NODE.NODE_NAME is '节点名称' +comment on column WF_TASK_BACK_NODE.ORDER_NO is '排序' +comment on column WF_TASK_BACK_NODE.SORT_NUM is '排序' +comment on column WF_TASK_BACK_NODE.INSTANCE_ID is '流程实例id' +comment on column WF_TASK_BACK_NODE.TASK_TYPE is '节点类型' +comment on column WF_TASK_BACK_NODE.ASSIGNEE is '审批人' +comment on column WF_TASK_BACK_NODE.TENANT_ID is '租户编号' +comment on column WF_TASK_BACK_NODE.CREATE_DEPT is '创建部门' +comment on column WF_TASK_BACK_NODE.CREATE_BY is '创建者' +comment on column WF_TASK_BACK_NODE.CREATE_TIME is '创建时间' +comment on column WF_TASK_BACK_NODE.UPDATE_BY is '更新者' +comment on column WF_TASK_BACK_NODE.UPDATE_TIME is '更新时间' + +create table WF_DEFINITION_CONFIG +( + ID NUMBER(20) NOT NULL + CONSTRAINT PK_WF_DEFINITION_CONFIG + PRIMARY KEY, + TABLE_NAME VARCHAR2(255) NOT NULL, + DEFINITION_ID VARCHAR2(255) NOT NULL, + PROCESS_KEY VARCHAR2(255) NOT NULL, + VERSION NUMBER(10) NOT NULL, + REMARK VARCHAR2(500), + TENANT_ID VARCHAR2(20), + CREATE_DEPT NUMBER(20), + CREATE_BY NUMBER(20), + CREATE_TIME DATE, + UPDATE_BY NUMBER(20), + UPDATE_TIME DATE, + constraint uni_definition_id + unique (definition_id) +); +comment on table WF_DEFINITION_CONFIG is '流程定义配置' +comment on column WF_DEFINITION_CONFIG.ID is '主键' +comment on column WF_DEFINITION_CONFIG.TABLE_NAME is '表名' +comment on column WF_DEFINITION_CONFIG.DEFINITION_ID is '流程定义ID' +comment on column WF_DEFINITION_CONFIG.PROCESS_KEY is '流程KEY' +comment on column WF_DEFINITION_CONFIG.VERSION is '流程版本' +comment on column WF_DEFINITION_CONFIG.TENANT_ID is '租户编号' +comment on column WF_DEFINITION_CONFIG.REMARK is '备注' +comment on column WF_DEFINITION_CONFIG.CREATE_DEPT is '创建部门' +comment on column WF_DEFINITION_CONFIG.CREATE_BY is '创建者' +comment on column WF_DEFINITION_CONFIG.CREATE_TIME is '创建时间' +comment on column WF_DEFINITION_CONFIG.UPDATE_BY is '更新者' +comment on column WF_DEFINITION_CONFIG.UPDATE_TIME is '更新时间' + +create table WF_FORM_MANAGE +( + ID NUMBER(20) NOT NULL + CONSTRAINT PK_WF_FORM_MANAGE + PRIMARY KEY, + FORM_NAME VARCHAR2(255) NOT NULL, + FORM_TYPE VARCHAR2(255) NOT NULL, + ROUTER VARCHAR2(255) NOT NULL, + REMARK VARCHAR2(500), + TENANT_ID VARCHAR2(20), + CREATE_DEPT NUMBER(20), + CREATE_BY NUMBER(20), + CREATE_TIME DATE, + UPDATE_BY NUMBER(20), + UPDATE_TIME DATE +); + +comment on table WF_FORM_MANAGE is '表单管理' +comment on column WF_FORM_MANAGE.ID is '主键' +comment on column WF_FORM_MANAGE.FORM_NAME is '表单名称' +comment on column WF_FORM_MANAGE.FORM_TYPE is '表单类型' +comment on column WF_FORM_MANAGE.ROUTER is '路由地址/表单ID' +comment on column WF_FORM_MANAGE.REMARK is '备注' +comment on column WF_FORM_MANAGE.TENANT_ID is '租户编号' +comment on column WF_FORM_MANAGE.CREATE_DEPT is '创建部门' +comment on column WF_FORM_MANAGE.CREATE_BY is '创建者' +comment on column WF_FORM_MANAGE.CREATE_TIME is '创建时间' +comment on column WF_FORM_MANAGE.UPDATE_BY is '更新者' +comment on column WF_FORM_MANAGE.UPDATE_TIME is '更新时间' + +insert into wf_form_manage(id, form_name, form_type, router, remark, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1, '请假申请', 'static', '/demo/leaveEdit/index', NULL, '000000', 103, 1, sysdate, 1, sysdate); + +create table WF_NODE_CONFIG +( + ID NUMBER(20) NOT NULL + CONSTRAINT PK_WF_NODE_CONFIG + PRIMARY KEY, + FORM_ID NUMBER(20), + FORM_TYPE VARCHAR2(255), + NODE_NAME VARCHAR2(255) NOT NULL, + NODE_ID VARCHAR2(255) NOT NULL, + DEFINITION_ID VARCHAR2(255) NOT NULL, + APPLY_USER_TASK CHAR(1) DEFAULT '0', + TENANT_ID VARCHAR2(20), + CREATE_DEPT NUMBER(20), + CREATE_BY NUMBER(20), + CREATE_TIME DATE, + UPDATE_BY NUMBER(20), + UPDATE_TIME DATE +); + +comment on table WF_NODE_CONFIG is '节点配置' +comment on column WF_NODE_CONFIG.ID is '主键' +comment on column WF_NODE_CONFIG.FORM_ID is '表单id' +comment on column WF_NODE_CONFIG.FORM_TYPE is '表单类型' +comment on column WF_NODE_CONFIG.NODE_ID is '节点id' +comment on column WF_NODE_CONFIG.NODE_NAME is '节点名称' +comment on column WF_NODE_CONFIG.DEFINITION_ID is '流程定义id' +comment on column WF_NODE_CONFIG.APPLY_USER_TASK is '是否为申请人节点 (0是 1否)' +comment on column WF_NODE_CONFIG.TENANT_ID is '租户编号' +comment on column WF_NODE_CONFIG.CREATE_DEPT is '创建部门' +comment on column WF_NODE_CONFIG.CREATE_BY is '创建者' +comment on column WF_NODE_CONFIG.CREATE_TIME is '创建时间' +comment on column WF_NODE_CONFIG.UPDATE_BY is '更新者' +comment on column WF_NODE_CONFIG.UPDATE_TIME is '更新时间' + +INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11638, '请假申请', 5, 1, 'leave', 'workflow/leave/index', 1, 0, 'C', '0', '0', 'demo:leave:list', '#', 103, 1, sysdate, NULL, NULL, '请假申请菜单'); +INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11639, '请假申请查询', 11638, 1, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:query', '#', 103, 1, sysdate, NULL, NULL, ''); +INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11640, '请假申请新增', 11638, 2, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:add', '#', 103, 1, sysdate, NULL, NULL, ''); +INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11641, '请假申请修改', 11638, 3, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:edit', '#', 103, 1, sysdate, NULL, NULL, ''); +INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11642, '请假申请删除', 11638, 4, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:remove', '#', 103, 1, sysdate, NULL, NULL, ''); +INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11643, '请假申请导出', 11638, 5, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:export', '#', 103, 1, sysdate, NULL, NULL, ''); + +INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (13, '000000', '业务状态', 'wf_business_status', 103, 1, sysdate, NULL, NULL, '业务状态列表'); +INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (14, '000000', '表单类型', 'wf_form_type', 103, 1, sysdate, NULL, NULL, '表单类型列表'); + +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (39, '000000', 1, '已撤销', 'cancel', 'wf_business_status', '', 'danger', 'N', 103, 1, sysdate, NULL, NULL, '已撤销'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (40, '000000', 2, '草稿', 'draft', 'wf_business_status', '', 'info', 'N', 103, 1, sysdate, NULL, NULL, '草稿'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (41, '000000', 3, '待审核', 'waiting', 'wf_business_status', '', 'primary', 'N', 103, 1,sysdate, NULL, NULL, '待审核'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (42, '000000', 4, '已完成', 'finish', 'wf_business_status', '', 'success', 'N', 103, 1, sysdate, NULL, NULL, '已完成'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (43, '000000', 5, '已作废', 'invalid', 'wf_business_status', '', 'danger', 'N', 103, 1, sysdate, NULL, NULL, '已作废'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (44, '000000', 6, '已退回', 'back', 'wf_business_status', '', 'danger', 'N', 103, 1, sysdate, NULL, NULL, '已退回'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (45, '000000', 7, '已终止', 'termination', 'wf_business_status', '', 'danger', 'N', 103, 1,sysdate, NULL, NULL, '已终止'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (46, '000000', 1, '自定义表单', 'static', 'wf_form_type', '', 'success', 'N', 103, 1, sysdate, NULL, NULL, '自定义表单'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (47, '000000', 2, '动态表单', 'dynamic', 'wf_form_type', '', 'primary', 'N', 103, 1, sysdate, NULL, NULL, '动态表单'); + +-- 表单管理 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(11628, '表单管理', '11616', '5', 'formManage', 'workflow/formManage/index', 1, 0, 'C', '0', '0', 'workflow:formManage:list', 'tree-table', 103, 1, sysdate, null, null, '表单管理菜单'); + +-- 表单管理按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(11644, '表单管理查询', 11628, '1', '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:query', '', 103, 1, sysdate, null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(11645, '表单管理新增', 11628, '2', '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:add', '', 103, 1, sysdate, null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(11646, '表单管理修改', 11628, '3', '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:edit', '', 103, 1, sysdate, null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(11647, '表单管理删除', 11628, '4', '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:remove', '', 103, 1, sysdate, null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(11648, '表单管理导出', 11628, '5', '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:export', 'tree-table', 103, 1, sysdate, null, null, ''); diff --git a/script/sql/oracle/oracle_ry_vue_5.X.sql b/script/sql/oracle/oracle_ry_vue_5.X.sql index ef45c5f8e..9dea0b55a 100644 --- a/script/sql/oracle/oracle_ry_vue_5.X.sql +++ b/script/sql/oracle/oracle_ry_vue_5.X.sql @@ -20,7 +20,7 @@ create table sys_social union_id varchar2(255) default null, scope varchar2(255) default null, token_type varchar2(255) default null, - id_token varchar2(255) default null, + id_token varchar2(2000) default null, mac_algorithm varchar2(255) default null, mac_key varchar2(255) default null, code varchar2(255) default null, @@ -269,8 +269,8 @@ comment on column sys_user.remark is '备注'; -- 初始化-用户信息表数据 -- ---------------------------- insert into sys_user values(1, '000000', 103, 'admin', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@163.com', '15888888888', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate, 103, 1, sysdate, null, null, '管理员'); -insert into sys_user values(2, '000000', 105, 'lionli', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@qq.com', '15666666666', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate, 103, 1, sysdate, null, null, '测试员'); - +insert into sys_user values(3, '000000', 108, 'test', '本部门及以下 密码666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', sysdate, 103, 1, sysdate, null, null, ''); +insert into sys_user values(4, '000000', 102, 'test1', '仅本人 密码666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', sysdate, 103, 1, sysdate, null, null, ''); -- ---------------------------- -- 3、岗位信息表 @@ -361,8 +361,8 @@ comment on column sys_role.remark is '备注'; -- 初始化-角色信息表数据 -- ---------------------------- insert into sys_role values('1', '000000', '超级管理员', 'superadmin', 1, 1, 1, 1, '0', '0', 103, 1, sysdate, null, null, '超级管理员'); -insert into sys_role values('2', '000000', '普通角色', 'common', 2, 2, 1, 1, '0', '0', 103, 1, sysdate, null, null, '普通角色'); - +insert into sys_role values('3', '000000', '本部门及以下', 'test1', 3, 4, 1, 1, '0', '0', 103, 1, sysdate, null, null, null); +insert into sys_role values('4', '000000', '仅本人', 'test2', 4, 5, 1, 1, '0', '0', 103, 1, sysdate, null, null, null); -- ---------------------------- -- 5、菜单权限表 @@ -423,6 +423,7 @@ insert into sys_menu values('6', '租户管理', '0', '2', 'tenant', n insert into sys_menu values('2', '系统监控', '0', '3', 'monitor', null, '', 1, 0, 'M', '0', '0', '', 'monitor', 103, 1, sysdate, null, null, '系统监控目录'); insert into sys_menu values('3', '系统工具', '0', '4', 'tool', null, '', 1, 0, 'M', '0', '0', '', 'tool', 103, 1, sysdate, null, null, '系统工具目录'); insert into sys_menu values('4', 'PLUS官网', '0', '5', 'https://gitee.com/dromara/RuoYi-Vue-Plus', null, '', 0, 0, 'M', '0', '0', '', 'guide', 103, 1, sysdate, null, null, 'RuoYi-Vue-Plus官网地址'); +insert into sys_menu values('5', '测试菜单', '0', '5', 'demo', null, '', 1, 0, 'M', '0', '0', null, 'star', 103, 1, sysdate, null, null, ''); -- 二级菜单 insert into sys_menu values('100', '用户管理', '1', '1', 'user', 'system/user/index', '', 1, 0, 'C', '0', '0', 'system:user:list', 'user', 103, 1, sysdate, null, null, '用户管理菜单'); insert into sys_menu values('101', '角色管理', '1', '2', 'role', 'system/role/index', '', 1, 0, 'C', '0', '0', 'system:role:list', 'peoples', 103, 1, sysdate, null, null, '角色管理菜单'); @@ -544,6 +545,20 @@ insert into sys_menu values('1062', '客户端管理新增', '123', '2', '#', ' insert into sys_menu values('1063', '客户端管理修改', '123', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:edit', '#', 103, 1, sysdate, null, null, ''); insert into sys_menu values('1064', '客户端管理删除', '123', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:remove', '#', 103, 1, sysdate, null, null, ''); insert into sys_menu values('1065', '客户端管理导出', '123', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:export', '#', 103, 1, sysdate, null, null, ''); +-- 测试菜单 +insert into sys_menu values('1500', '测试单表', '5', '1', 'demo', 'demo/demo/index', '', 1, 0, 'C', '0', '0', 'demo:demo:list', '#', 103, 1, sysdate, null, null, '测试单表菜单'); +insert into sys_menu values('1501', '测试单表查询', '1500', '1', '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1502', '测试单表新增', '1500', '2', '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1503', '测试单表修改', '1500', '3', '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1504', '测试单表删除', '1500', '4', '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:remove', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1505', '测试单表导出', '1500', '5', '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:export', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1506', '测试树表', '5', '1', 'tree', 'demo/tree/index', '', 1, 0, 'C', '0', '0', 'demo:tree:list', '#', 103, 1, sysdate, null, null, '测试树表菜单'); +insert into sys_menu values('1507', '测试树表查询', '1506', '1', '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1508', '测试树表新增', '1506', '2', '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1509', '测试树表修改', '1506', '3', '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1510', '测试树表删除', '1506', '4', '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:remove', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1511', '测试树表导出', '1506', '5', '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:export', '#', 103, 1, sysdate, null, null, ''); + -- ---------------------------- -- 6、用户和角色关联表 用户N-1角色 @@ -563,8 +578,8 @@ comment on column sys_user_role.role_id is '角色ID'; -- 初始化-用户和角色关联表数据 -- ---------------------------- insert into sys_user_role values ('1', '1'); -insert into sys_user_role values ('2', '2'); - +insert into sys_user_role values ('3', '3'); +insert into sys_user_role values ('4', '4'); -- ---------------------------- -- 7、角色和菜单关联表 角色1-N菜单 @@ -583,90 +598,89 @@ comment on column sys_role_menu.menu_id is '菜单ID'; -- ---------------------------- -- 初始化-角色和菜单关联表数据 -- ---------------------------- -insert into sys_role_menu values ('2', '1'); -insert into sys_role_menu values ('2', '2'); -insert into sys_role_menu values ('2', '3'); -insert into sys_role_menu values ('2', '4'); -insert into sys_role_menu values ('2', '100'); -insert into sys_role_menu values ('2', '101'); -insert into sys_role_menu values ('2', '102'); -insert into sys_role_menu values ('2', '103'); -insert into sys_role_menu values ('2', '104'); -insert into sys_role_menu values ('2', '105'); -insert into sys_role_menu values ('2', '106'); -insert into sys_role_menu values ('2', '107'); -insert into sys_role_menu values ('2', '108'); -insert into sys_role_menu values ('2', '109'); -insert into sys_role_menu values ('2', '110'); -insert into sys_role_menu values ('2', '111'); -insert into sys_role_menu values ('2', '112'); -insert into sys_role_menu values ('2', '113'); -insert into sys_role_menu values ('2', '114'); -insert into sys_role_menu values ('2', '115'); -insert into sys_role_menu values ('2', '116'); -insert into sys_role_menu values ('2', '500'); -insert into sys_role_menu values ('2', '501'); -insert into sys_role_menu values ('2', '1000'); -insert into sys_role_menu values ('2', '1001'); -insert into sys_role_menu values ('2', '1002'); -insert into sys_role_menu values ('2', '1003'); -insert into sys_role_menu values ('2', '1004'); -insert into sys_role_menu values ('2', '1005'); -insert into sys_role_menu values ('2', '1006'); -insert into sys_role_menu values ('2', '1007'); -insert into sys_role_menu values ('2', '1008'); -insert into sys_role_menu values ('2', '1009'); -insert into sys_role_menu values ('2', '1010'); -insert into sys_role_menu values ('2', '1011'); -insert into sys_role_menu values ('2', '1012'); -insert into sys_role_menu values ('2', '1013'); -insert into sys_role_menu values ('2', '1014'); -insert into sys_role_menu values ('2', '1015'); -insert into sys_role_menu values ('2', '1016'); -insert into sys_role_menu values ('2', '1017'); -insert into sys_role_menu values ('2', '1018'); -insert into sys_role_menu values ('2', '1019'); -insert into sys_role_menu values ('2', '1020'); -insert into sys_role_menu values ('2', '1021'); -insert into sys_role_menu values ('2', '1022'); -insert into sys_role_menu values ('2', '1023'); -insert into sys_role_menu values ('2', '1024'); -insert into sys_role_menu values ('2', '1025'); -insert into sys_role_menu values ('2', '1026'); -insert into sys_role_menu values ('2', '1027'); -insert into sys_role_menu values ('2', '1028'); -insert into sys_role_menu values ('2', '1029'); -insert into sys_role_menu values ('2', '1030'); -insert into sys_role_menu values ('2', '1031'); -insert into sys_role_menu values ('2', '1032'); -insert into sys_role_menu values ('2', '1033'); -insert into sys_role_menu values ('2', '1034'); -insert into sys_role_menu values ('2', '1035'); -insert into sys_role_menu values ('2', '1036'); -insert into sys_role_menu values ('2', '1037'); -insert into sys_role_menu values ('2', '1038'); -insert into sys_role_menu values ('2', '1039'); -insert into sys_role_menu values ('2', '1040'); -insert into sys_role_menu values ('2', '1041'); -insert into sys_role_menu values ('2', '1042'); -insert into sys_role_menu values ('2', '1043'); -insert into sys_role_menu values ('2', '1044'); -insert into sys_role_menu values ('2', '1045'); -insert into sys_role_menu values ('2', '1050'); -insert into sys_role_menu values ('2', '1046'); -insert into sys_role_menu values ('2', '1047'); -insert into sys_role_menu values ('2', '1048'); -insert into sys_role_menu values ('2', '1055'); -insert into sys_role_menu values ('2', '1056'); -insert into sys_role_menu values ('2', '1057'); -insert into sys_role_menu values ('2', '1058'); -insert into sys_role_menu values ('2', '1059'); -insert into sys_role_menu values ('2', '1060'); -insert into sys_role_menu values ('2', '1061'); -insert into sys_role_menu values ('2', '1062'); -insert into sys_role_menu values ('2', '1063'); -insert into sys_role_menu values ('2', '1064'); -insert into sys_role_menu values ('2', '1065'); +insert into sys_role_menu values ('3', '1'); +insert into sys_role_menu values ('3', '5'); +insert into sys_role_menu values ('3', '100'); +insert into sys_role_menu values ('3', '101'); +insert into sys_role_menu values ('3', '102'); +insert into sys_role_menu values ('3', '103'); +insert into sys_role_menu values ('3', '104'); +insert into sys_role_menu values ('3', '105'); +insert into sys_role_menu values ('3', '106'); +insert into sys_role_menu values ('3', '107'); +insert into sys_role_menu values ('3', '108'); +insert into sys_role_menu values ('3', '500'); +insert into sys_role_menu values ('3', '501'); +insert into sys_role_menu values ('3', '1001'); +insert into sys_role_menu values ('3', '1002'); +insert into sys_role_menu values ('3', '1003'); +insert into sys_role_menu values ('3', '1004'); +insert into sys_role_menu values ('3', '1005'); +insert into sys_role_menu values ('3', '1006'); +insert into sys_role_menu values ('3', '1007'); +insert into sys_role_menu values ('3', '1008'); +insert into sys_role_menu values ('3', '1009'); +insert into sys_role_menu values ('3', '1010'); +insert into sys_role_menu values ('3', '1011'); +insert into sys_role_menu values ('3', '1012'); +insert into sys_role_menu values ('3', '1013'); +insert into sys_role_menu values ('3', '1014'); +insert into sys_role_menu values ('3', '1015'); +insert into sys_role_menu values ('3', '1016'); +insert into sys_role_menu values ('3', '1017'); +insert into sys_role_menu values ('3', '1018'); +insert into sys_role_menu values ('3', '1019'); +insert into sys_role_menu values ('3', '1020'); +insert into sys_role_menu values ('3', '1021'); +insert into sys_role_menu values ('3', '1022'); +insert into sys_role_menu values ('3', '1023'); +insert into sys_role_menu values ('3', '1024'); +insert into sys_role_menu values ('3', '1025'); +insert into sys_role_menu values ('3', '1026'); +insert into sys_role_menu values ('3', '1027'); +insert into sys_role_menu values ('3', '1028'); +insert into sys_role_menu values ('3', '1029'); +insert into sys_role_menu values ('3', '1030'); +insert into sys_role_menu values ('3', '1031'); +insert into sys_role_menu values ('3', '1032'); +insert into sys_role_menu values ('3', '1033'); +insert into sys_role_menu values ('3', '1034'); +insert into sys_role_menu values ('3', '1035'); +insert into sys_role_menu values ('3', '1036'); +insert into sys_role_menu values ('3', '1037'); +insert into sys_role_menu values ('3', '1038'); +insert into sys_role_menu values ('3', '1039'); +insert into sys_role_menu values ('3', '1040'); +insert into sys_role_menu values ('3', '1041'); +insert into sys_role_menu values ('3', '1042'); +insert into sys_role_menu values ('3', '1043'); +insert into sys_role_menu values ('3', '1044'); +insert into sys_role_menu values ('3', '1045'); +insert into sys_role_menu values ('3', '1500'); +insert into sys_role_menu values ('3', '1501'); +insert into sys_role_menu values ('3', '1502'); +insert into sys_role_menu values ('3', '1503'); +insert into sys_role_menu values ('3', '1504'); +insert into sys_role_menu values ('3', '1505'); +insert into sys_role_menu values ('3', '1506'); +insert into sys_role_menu values ('3', '1507'); +insert into sys_role_menu values ('3', '1508'); +insert into sys_role_menu values ('3', '1509'); +insert into sys_role_menu values ('3', '1510'); +insert into sys_role_menu values ('3', '1511'); +insert into sys_role_menu values ('4', '5'); +insert into sys_role_menu values ('4', '1500'); +insert into sys_role_menu values ('4', '1501'); +insert into sys_role_menu values ('4', '1502'); +insert into sys_role_menu values ('4', '1503'); +insert into sys_role_menu values ('4', '1504'); +insert into sys_role_menu values ('4', '1505'); +insert into sys_role_menu values ('4', '1506'); +insert into sys_role_menu values ('4', '1507'); +insert into sys_role_menu values ('4', '1508'); +insert into sys_role_menu values ('4', '1509'); +insert into sys_role_menu values ('4', '1510'); +insert into sys_role_menu values ('4', '1511'); -- ---------------------------- -- 8、角色和部门关联表 角色1-N部门 @@ -682,13 +696,6 @@ comment on table sys_role_dept is '角色和部门关联表'; comment on column sys_role_dept.role_id is '角色ID'; comment on column sys_role_dept.dept_id is '部门ID'; --- ---------------------------- --- 初始化-角色和部门关联表数据 --- ---------------------------- -insert into sys_role_dept values ('2', '100'); -insert into sys_role_dept values ('2', '101'); -insert into sys_role_dept values ('2', '105'); - -- ---------------------------- -- 9、用户与岗位关联表 用户1-N岗位 @@ -708,8 +715,6 @@ comment on column sys_user_post.post_id is '岗位ID'; -- 初始化-用户与岗位关联表数据 -- ---------------------------- insert into sys_user_post values ('1', '1'); -insert into sys_user_post values ('2', '2'); - -- ---------------------------- -- 10、操作日志记录 @@ -1244,6 +1249,102 @@ comment on column sys_client.update_time is '更新时间'; insert into sys_client values (1, 'e5cd7e4891bf95d1d19206ce24a7b32e', 'pc', 'pc123', 'password,social', 'pc', 1800, 604800, 0, 0, 103, 1, sysdate, 1, sysdate); insert into sys_client values (2, '428a8310cd442757ae699df5d894f051', 'app', 'app123', 'password,sms,social', 'android', 1800, 604800, 0, 0, 103, 1, sysdate, 1, sysdate); +create table test_demo ( + id number(20) not null, + tenant_id varchar2(20) default '000000', + dept_id number(20) default null, + user_id number(20) default null, + order_num number(10) default 0, + test_key varchar2(255) default null, + value varchar2(255) default null, + version number(10) default 0, + create_dept number(20) default null, + create_time date, + create_by number(20) default null, + update_time date, + update_by number(20) default null, + del_flag number(2) default 0 +); + +alter table test_demo add constraint pk_test_demo primary key (id); + +comment on table test_demo is '测试单表'; +comment on column test_demo.id is '主键'; +comment on column test_demo.tenant_id is '租户编号'; +comment on column test_demo.dept_id is '部门id'; +comment on column test_demo.user_id is '用户id'; +comment on column test_demo.order_num is '排序号'; +comment on column test_demo.test_key is 'key键'; +comment on column test_demo.value is '值'; +comment on column test_demo.version is '版本'; +comment on column test_demo.create_dept is '创建部门'; +comment on column test_demo.create_time is '创建时间'; +comment on column test_demo.create_by is '创建人'; +comment on column test_demo.update_time is '更新时间'; +comment on column test_demo.update_by is '更新人'; +comment on column test_demo.del_flag is '删除标志'; + +create table test_tree ( + id number(20) not null, + tenant_id varchar2(20) default '000000', + parent_id number(20) default 0, + dept_id number(20) default null, + user_id number(20) default null, + tree_name varchar2(255) default null, + version number(10) default 0, + create_dept number(20) default null, + create_time date, + create_by number(20) default null, + update_time date, + update_by number(20) default null, + del_flag number(2) default 0 +); + +alter table test_tree add constraint pk_test_tree primary key (id); + +comment on table test_tree is '测试树表'; +comment on column test_tree.id is '主键'; +comment on column test_tree.tenant_id is '租户编号'; +comment on column test_tree.parent_id is '父id'; +comment on column test_tree.dept_id is '部门id'; +comment on column test_tree.user_id is '用户id'; +comment on column test_tree.tree_name is '值'; +comment on column test_tree.version is '版本'; +comment on column test_tree.create_dept is '创建部门'; +comment on column test_tree.create_time is '创建时间'; +comment on column test_tree.create_by is '创建人'; +comment on column test_tree.update_time is '更新时间'; +comment on column test_tree.update_by is '更新人'; +comment on column test_tree.del_flag is '删除标志'; + +insert into test_demo values (1, '000000', 102, 4, 1, '测试数据权限', '测试', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (2, '000000', 102, 3, 2, '子节点1', '111', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (3, '000000', 102, 3, 3, '子节点2', '222', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (4, '000000', 108, 4, 4, '测试数据', 'demo', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (5, '000000', 108, 3, 13, '子节点11', '1111', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (6, '000000', 108, 3, 12, '子节点22', '2222', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (7, '000000', 108, 3, 11, '子节点33', '3333', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (8, '000000', 108, 3, 10, '子节点44', '4444', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (9, '000000', 108, 3, 9, '子节点55', '5555', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (10, '000000', 108, 3, 8, '子节点66', '6666', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (11, '000000', 108, 3, 7, '子节点77', '7777', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (12, '000000', 108, 3, 6, '子节点88', '8888', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (13, '000000', 108, 3, 5, '子节点99', '9999', 0, 103, sysdate, 1, null, null, 0); + +insert into test_tree values (1, '000000', 0, 102, 4, '测试数据权限', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (2, '000000', 1, 102, 3, '子节点1', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (3, '000000', 2, 102, 3, '子节点2', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (4, '000000', 0, 108, 4, '测试树1', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (5, '000000', 4, 108, 3, '子节点11', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (6, '000000', 4, 108, 3, '子节点22', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (7, '000000', 4, 108, 3, '子节点33', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (8, '000000', 5, 108, 3, '子节点44', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (9, '000000', 6, 108, 3, '子节点55', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (10, '000000', 7, 108, 3, '子节点66', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (11, '000000', 7, 108, 3, '子节点77', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (12, '000000', 10, 108, 3, '子节点88', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (13, '000000', 10, 108, 3, '子节点99', 0, 103, sysdate, 1, null, null, 0); + -- ---------------------------- -- 钩子 ,用于session连接之后 自动设置默认的date类型格式化 简化时间查询 diff --git a/script/sql/oracle/oracle_test.sql b/script/sql/oracle/oracle_test.sql deleted file mode 100644 index fd93786d9..000000000 --- a/script/sql/oracle/oracle_test.sql +++ /dev/null @@ -1,204 +0,0 @@ -create table test_demo ( - id number(20) not null, - tenant_id varchar2(20) default '000000', - dept_id number(20) default null, - user_id number(20) default null, - order_num number(10) default 0, - test_key varchar2(255) default null, - value varchar2(255) default null, - version number(10) default 0, - create_dept number(20) default null, - create_time date, - create_by number(20) default null, - update_time date, - update_by number(20) default null, - del_flag number(2) default 0 -); - -alter table test_demo add constraint pk_test_demo primary key (id); - -comment on table test_demo is '测试单表'; -comment on column test_demo.id is '主键'; -comment on column test_demo.tenant_id is '租户编号'; -comment on column test_demo.dept_id is '部门id'; -comment on column test_demo.user_id is '用户id'; -comment on column test_demo.order_num is '排序号'; -comment on column test_demo.test_key is 'key键'; -comment on column test_demo.value is '值'; -comment on column test_demo.version is '版本'; -comment on column test_demo.create_dept is '创建部门'; -comment on column test_demo.create_time is '创建时间'; -comment on column test_demo.create_by is '创建人'; -comment on column test_demo.update_time is '更新时间'; -comment on column test_demo.update_by is '更新人'; -comment on column test_demo.del_flag is '删除标志'; - -create table test_tree ( - id number(20) not null, - tenant_id varchar2(20) default '000000', - parent_id number(20) default 0, - dept_id number(20) default null, - user_id number(20) default null, - tree_name varchar2(255) default null, - version number(10) default 0, - create_dept number(20) default null, - create_time date, - create_by number(20) default null, - update_time date, - update_by number(20) default null, - del_flag number(2) default 0 -); - -alter table test_tree add constraint pk_test_tree primary key (id); - -comment on table test_tree is '测试树表'; -comment on column test_tree.id is '主键'; -comment on column test_tree.tenant_id is '租户编号'; -comment on column test_tree.parent_id is '父id'; -comment on column test_tree.dept_id is '部门id'; -comment on column test_tree.user_id is '用户id'; -comment on column test_tree.tree_name is '值'; -comment on column test_tree.version is '版本'; -comment on column test_tree.create_dept is '创建部门'; -comment on column test_tree.create_time is '创建时间'; -comment on column test_tree.create_by is '创建人'; -comment on column test_tree.update_time is '更新时间'; -comment on column test_tree.update_by is '更新人'; -comment on column test_tree.del_flag is '删除标志'; - -insert into sys_user(user_id, tenant_id, dept_id, user_name, nick_name, user_type, email, phonenumber, sex, avatar, password, status, del_flag, login_ip, login_date, create_dept, create_by, create_time, update_by, update_time, remark) values (3, '000000', 108, 'test', '本部门及以下 密码666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', sysdate, 103, 1, sysdate, 3, sysdate, null); -insert into sys_user(user_id, tenant_id, dept_id, user_name, nick_name, user_type, email, phonenumber, sex, avatar, password, status, del_flag, login_ip, login_date, create_dept, create_by, create_time, update_by, update_time, remark) values (4, '000000', 102, 'test1', '仅本人 密码666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', sysdate, 103, 1, sysdate, 4, sysdate, null); - -insert into sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) values (5, '测试菜单', 0, 5, 'demo', null, 1, 0, 'M', '0', '0', null, 'star', 103, 1, sysdate, 1, sysdate, ''); - -insert into sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) values (1500, '测试单表', 5, 1, 'demo', 'demo/demo/index', 1, 0, 'C', '0', '0', 'demo:demo:list', '#', 103, 1, sysdate, null, null, '测试单表菜单'); -insert into sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) values (1501, '测试单表查询', 1500, 1, '#', '', 1, 0, 'F', '0', '0', 'demo:demo:query', '#', 103, 1, sysdate, null, null, ''); -insert into sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) values (1502, '测试单表新增', 1500, 2, '#', '', 1, 0, 'F', '0', '0', 'demo:demo:add', '#', 103, 1, sysdate, null, null, ''); -insert into sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) values (1503, '测试单表修改', 1500, 3, '#', '', 1, 0, 'F', '0', '0', 'demo:demo:edit', '#', 103, 1, sysdate, null, null, ''); -insert into sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) values (1504, '测试单表删除', 1500, 4, '#', '', 1, 0, 'F', '0', '0', 'demo:demo:remove', '#', 103, 1, sysdate, null, null, ''); -insert into sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) values (1505, '测试单表导出', 1500, 5, '#', '', 1, 0, 'F', '0', '0', 'demo:demo:export', '#', 103, 1, sysdate, null, null, ''); - -insert into sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) values (1506, '测试树表', 5, 1, 'tree', 'demo/tree/index', 1, 0, 'C', '0', '0', 'demo:tree:list', '#', 103, 1, sysdate, null, null, '测试树表菜单'); -insert into sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) values (1507, '测试树表查询', 1506, 1, '#', '', 1, 0, 'F', '0', '0', 'demo:tree:query', '#', 103, 1, sysdate, null, null, ''); -insert into sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) values (1508, '测试树表新增', 1506, 2, '#', '', 1, 0, 'F', '0', '0', 'demo:tree:add', '#', 103, 1, sysdate, null, null, ''); -insert into sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) values (1509, '测试树表修改', 1506, 3, '#', '', 1, 0, 'F', '0', '0', 'demo:tree:edit', '#', 103, 1, sysdate, null, null, ''); -insert into sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) values (1510, '测试树表删除', 1506, 4, '#', '', 1, 0, 'F', '0', '0', 'demo:tree:remove', '#', 103, 1, sysdate, null, null, ''); -insert into sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) values (1511, '测试树表导出', 1506, 5, '#', '', 1, 0, 'F', '0', '0', 'demo:tree:export', '#', 103, 1, sysdate, null, null, ''); - -insert into sys_role(role_id, tenant_id, role_name, role_key, role_sort, data_scope, menu_check_strictly, dept_check_strictly, status, del_flag, create_dept, create_by, create_time, update_by, update_time, remark) values (3, '000000', '本部门及以下', 'test1', 3, '4', 1, 1, '0', '0', 103, 1, sysdate, null, null, null); -insert into sys_role(role_id, tenant_id, role_name, role_key, role_sort, data_scope, menu_check_strictly, dept_check_strictly, status, del_flag, create_dept, create_by, create_time, update_by, update_time, remark) values (4, '000000', '仅本人', 'test2', 4, '5', 1, 1, '0', '0', 103, 1, sysdate, null, null, null); - -insert into sys_role_menu(role_id, menu_id) values (3, 1); -insert into sys_role_menu(role_id, menu_id) values (3, 5); -insert into sys_role_menu(role_id, menu_id) values (3, 100); -insert into sys_role_menu(role_id, menu_id) values (3, 101); -insert into sys_role_menu(role_id, menu_id) values (3, 102); -insert into sys_role_menu(role_id, menu_id) values (3, 103); -insert into sys_role_menu(role_id, menu_id) values (3, 104); -insert into sys_role_menu(role_id, menu_id) values (3, 105); -insert into sys_role_menu(role_id, menu_id) values (3, 106); -insert into sys_role_menu(role_id, menu_id) values (3, 107); -insert into sys_role_menu(role_id, menu_id) values (3, 108); -insert into sys_role_menu(role_id, menu_id) values (3, 500); -insert into sys_role_menu(role_id, menu_id) values (3, 501); -insert into sys_role_menu(role_id, menu_id) values (3, 1001); -insert into sys_role_menu(role_id, menu_id) values (3, 1002); -insert into sys_role_menu(role_id, menu_id) values (3, 1003); -insert into sys_role_menu(role_id, menu_id) values (3, 1004); -insert into sys_role_menu(role_id, menu_id) values (3, 1005); -insert into sys_role_menu(role_id, menu_id) values (3, 1006); -insert into sys_role_menu(role_id, menu_id) values (3, 1007); -insert into sys_role_menu(role_id, menu_id) values (3, 1008); -insert into sys_role_menu(role_id, menu_id) values (3, 1009); -insert into sys_role_menu(role_id, menu_id) values (3, 1010); -insert into sys_role_menu(role_id, menu_id) values (3, 1011); -insert into sys_role_menu(role_id, menu_id) values (3, 1012); -insert into sys_role_menu(role_id, menu_id) values (3, 1013); -insert into sys_role_menu(role_id, menu_id) values (3, 1014); -insert into sys_role_menu(role_id, menu_id) values (3, 1015); -insert into sys_role_menu(role_id, menu_id) values (3, 1016); -insert into sys_role_menu(role_id, menu_id) values (3, 1017); -insert into sys_role_menu(role_id, menu_id) values (3, 1018); -insert into sys_role_menu(role_id, menu_id) values (3, 1019); -insert into sys_role_menu(role_id, menu_id) values (3, 1020); -insert into sys_role_menu(role_id, menu_id) values (3, 1021); -insert into sys_role_menu(role_id, menu_id) values (3, 1022); -insert into sys_role_menu(role_id, menu_id) values (3, 1023); -insert into sys_role_menu(role_id, menu_id) values (3, 1024); -insert into sys_role_menu(role_id, menu_id) values (3, 1025); -insert into sys_role_menu(role_id, menu_id) values (3, 1026); -insert into sys_role_menu(role_id, menu_id) values (3, 1027); -insert into sys_role_menu(role_id, menu_id) values (3, 1028); -insert into sys_role_menu(role_id, menu_id) values (3, 1029); -insert into sys_role_menu(role_id, menu_id) values (3, 1030); -insert into sys_role_menu(role_id, menu_id) values (3, 1031); -insert into sys_role_menu(role_id, menu_id) values (3, 1032); -insert into sys_role_menu(role_id, menu_id) values (3, 1033); -insert into sys_role_menu(role_id, menu_id) values (3, 1034); -insert into sys_role_menu(role_id, menu_id) values (3, 1035); -insert into sys_role_menu(role_id, menu_id) values (3, 1036); -insert into sys_role_menu(role_id, menu_id) values (3, 1037); -insert into sys_role_menu(role_id, menu_id) values (3, 1038); -insert into sys_role_menu(role_id, menu_id) values (3, 1039); -insert into sys_role_menu(role_id, menu_id) values (3, 1040); -insert into sys_role_menu(role_id, menu_id) values (3, 1041); -insert into sys_role_menu(role_id, menu_id) values (3, 1042); -insert into sys_role_menu(role_id, menu_id) values (3, 1043); -insert into sys_role_menu(role_id, menu_id) values (3, 1044); -insert into sys_role_menu(role_id, menu_id) values (3, 1045); -insert into sys_role_menu(role_id, menu_id) values (3, 1500); -insert into sys_role_menu(role_id, menu_id) values (3, 1501); -insert into sys_role_menu(role_id, menu_id) values (3, 1502); -insert into sys_role_menu(role_id, menu_id) values (3, 1503); -insert into sys_role_menu(role_id, menu_id) values (3, 1504); -insert into sys_role_menu(role_id, menu_id) values (3, 1505); -insert into sys_role_menu(role_id, menu_id) values (3, 1506); -insert into sys_role_menu(role_id, menu_id) values (3, 1507); -insert into sys_role_menu(role_id, menu_id) values (3, 1508); -insert into sys_role_menu(role_id, menu_id) values (3, 1509); -insert into sys_role_menu(role_id, menu_id) values (3, 1510); -insert into sys_role_menu(role_id, menu_id) values (3, 1511); -insert into sys_role_menu(role_id, menu_id) values (4, 5); -insert into sys_role_menu(role_id, menu_id) values (4, 1500); -insert into sys_role_menu(role_id, menu_id) values (4, 1501); -insert into sys_role_menu(role_id, menu_id) values (4, 1502); -insert into sys_role_menu(role_id, menu_id) values (4, 1503); -insert into sys_role_menu(role_id, menu_id) values (4, 1504); -insert into sys_role_menu(role_id, menu_id) values (4, 1505); -insert into sys_role_menu(role_id, menu_id) values (4, 1506); -insert into sys_role_menu(role_id, menu_id) values (4, 1507); -insert into sys_role_menu(role_id, menu_id) values (4, 1508); -insert into sys_role_menu(role_id, menu_id) values (4, 1509); -insert into sys_role_menu(role_id, menu_id) values (4, 1510); -insert into sys_role_menu(role_id, menu_id) values (4, 1511); - -insert into sys_user_role(user_id, role_id) values (3, 3); -insert into sys_user_role(user_id, role_id) values (4, 4); - -insert into test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) values (1, '000000', 102, 4, 1, '测试数据权限', '测试', 0, 103, sysdate, 1, null, null, 0); -insert into test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) values (2, '000000', 102, 3, 2, '子节点1', '111', 0, 103, sysdate, 1, null, null, 0); -insert into test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) values (3, '000000', 102, 3, 3, '子节点2', '222', 0, 103, sysdate, 1, null, null, 0); -insert into test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) values (4, '000000', 108, 4, 4, '测试数据', 'demo', 0, 103, sysdate, 1, null, null, 0); -insert into test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) values (5, '000000', 108, 3, 13, '子节点11', '1111', 0, 103, sysdate, 1, null, null, 0); -insert into test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) values (6, '000000', 108, 3, 12, '子节点22', '2222', 0, 103, sysdate, 1, null, null, 0); -insert into test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) values (7, '000000', 108, 3, 11, '子节点33', '3333', 0, 103, sysdate, 1, null, null, 0); -insert into test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) values (8, '000000', 108, 3, 10, '子节点44', '4444', 0, 103, sysdate, 1, null, null, 0); -insert into test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) values (9, '000000', 108, 3, 9, '子节点55', '5555', 0, 103, sysdate, 1, null, null, 0); -insert into test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) values (10, '000000', 108, 3, 8, '子节点66', '6666', 0, 103, sysdate, 1, null, null, 0); -insert into test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) values (11, '000000', 108, 3, 7, '子节点77', '7777', 0, 103, sysdate, 1, null, null, 0); -insert into test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) values (12, '000000', 108, 3, 6, '子节点88', '8888', 0, 103, sysdate, 1, null, null, 0); -insert into test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) values (13, '000000', 108, 3, 5, '子节点99', '9999', 0, 103, sysdate, 1, null, null, 0); - -insert into test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) values (1, '000000', 0, 102, 4, '测试数据权限', 0, 103, sysdate, 1, null, null, 0); -insert into test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) values (2, '000000', 1, 102, 3, '子节点1', 0, 103, sysdate, 1, null, null, 0); -insert into test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) values (3, '000000', 2, 102, 3, '子节点2', 0, 103, sysdate, 1, null, null, 0); -insert into test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) values (4, '000000', 0, 108, 4, '测试树1', 0, 103, sysdate, 1, null, null, 0); -insert into test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) values (5, '000000', 4, 108, 3, '子节点11', 0, 103, sysdate, 1, null, null, 0); -insert into test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) values (6, '000000', 4, 108, 3, '子节点22', 0, 103, sysdate, 1, null, null, 0); -insert into test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) values (7, '000000', 4, 108, 3, '子节点33', 0, 103, sysdate, 1, null, null, 0); -insert into test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) values (8, '000000', 5, 108, 3, '子节点44', 0, 103, sysdate, 1, null, null, 0); -insert into test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) values (9, '000000', 6, 108, 3, '子节点55', 0, 103, sysdate, 1, null, null, 0); -insert into test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) values (10, '000000', 7, 108, 3, '子节点66', 0, 103, sysdate, 1, null, null, 0); -insert into test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) values (11, '000000', 7, 108, 3, '子节点77', 0, 103, sysdate, 1, null, null, 0); -insert into test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) values (12, '000000', 10, 108, 3, '子节点88', 0, 103, sysdate, 1, null, null, 0); -insert into test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) values (13, '000000', 10, 108, 3, '子节点99', 0, 103, sysdate, 1, null, null, 0); diff --git a/script/sql/postgres/easy_retry_postgre.sql b/script/sql/postgres/easy_retry_postgre.sql new file mode 100644 index 000000000..62801e941 --- /dev/null +++ b/script/sql/postgres/easy_retry_postgre.sql @@ -0,0 +1,805 @@ +-- PostgreSQL DDL + +CREATE TABLE er_namespace +( + id BIGSERIAL PRIMARY KEY, + name VARCHAR(64) NOT NULL, + unique_id VARCHAR(64) NOT NULL, + description VARCHAR(256) NOT NULL DEFAULT '', + create_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted SMALLINT NOT NULL DEFAULT 0 +); + +CREATE UNIQUE INDEX uk_namespace_unique_id ON er_namespace (unique_id); + +COMMENT ON COLUMN er_namespace.id IS '主键'; +COMMENT ON COLUMN er_namespace.name IS '名称'; +COMMENT ON COLUMN er_namespace.unique_id IS '唯一id'; +COMMENT ON COLUMN er_namespace.description IS '描述'; +COMMENT ON COLUMN er_namespace.create_dt IS '创建时间'; +COMMENT ON COLUMN er_namespace.update_dt IS '修改时间'; +COMMENT ON COLUMN er_namespace.deleted IS '逻辑删除 1、删除'; +COMMENT ON TABLE er_namespace IS '命名空间'; + +INSERT INTO er_namespace VALUES (1, 'Development', 'dev', '', now(), now(), 0); +INSERT INTO er_namespace VALUES (2, 'Production', 'prod', '', now(), now(), 0); + +CREATE TABLE er_group_config +( + id BIGSERIAL PRIMARY KEY, + namespace_id VARCHAR(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR(64) NOT NULL, + description VARCHAR(256) DEFAULT '', + token VARCHAR(64) DEFAULT 'ER_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', + group_status SMALLINT NOT NULL DEFAULT 0, + version INT NOT NULL, + group_partition INT NOT NULL, + id_generator_mode SMALLINT NOT NULL DEFAULT 1, + init_scene SMALLINT NOT NULL DEFAULT 0, + bucket_index INT NOT NULL DEFAULT 0, + create_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_namespace_id_group_name_group_config ON er_group_config (namespace_id, group_name); + +COMMENT ON COLUMN er_group_config.id IS '主键'; +COMMENT ON COLUMN er_group_config.namespace_id IS '命名空间'; +COMMENT ON COLUMN er_group_config.group_name IS '组名称'; +COMMENT ON COLUMN er_group_config.description IS '组描述'; +COMMENT ON COLUMN er_group_config.token IS 'token'; +COMMENT ON COLUMN er_group_config.group_status IS '组状态 0、未启用 1、启用'; +COMMENT ON COLUMN er_group_config.version IS '版本号'; +COMMENT ON COLUMN er_group_config.group_partition IS '分区'; +COMMENT ON COLUMN er_group_config.id_generator_mode IS '唯一id生成模式 默认号段模式'; +COMMENT ON COLUMN er_group_config.init_scene IS '是否初始化场景 0:否 1:是'; +COMMENT ON COLUMN er_group_config.bucket_index IS 'bucket'; +COMMENT ON COLUMN er_group_config.create_dt IS '创建时间'; +COMMENT ON COLUMN er_group_config.update_dt IS '修改时间'; +COMMENT ON TABLE er_group_config IS '组配置'; + +INSERT INTO er_group_config VALUES (1, 'dev', 'ruoyi_group', '', 'ER_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, 4, now(), now()); + +CREATE TABLE er_notify_config +( + id BIGSERIAL PRIMARY KEY, + namespace_id VARCHAR(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR(64) NOT NULL, + scene_name VARCHAR(64) NOT NULL, + notify_status SMALLINT NOT NULL DEFAULT 0, + notify_type SMALLINT NOT NULL DEFAULT 0, + notify_attribute VARCHAR(512) NOT NULL, + notify_threshold INT NOT NULL DEFAULT 0, + notify_scene SMALLINT NOT NULL DEFAULT 0, + rate_limiter_status SMALLINT NOT NULL DEFAULT 0, + rate_limiter_threshold INT NOT NULL DEFAULT 0, + description VARCHAR(256) NOT NULL DEFAULT '', + create_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_namespace_id_group_name_notify_config ON er_notify_config (namespace_id, group_name); + +COMMENT ON COLUMN er_notify_config.id IS '主键'; +COMMENT ON COLUMN er_notify_config.group_name IS '组名称'; +COMMENT ON COLUMN er_notify_config.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_notify_config.scene_name IS '场景名称'; +COMMENT ON COLUMN er_notify_config.notify_status IS '通知状态 0、未启用 1、启用'; +COMMENT ON COLUMN er_notify_config.notify_type IS '通知类型 1、钉钉 2、邮件 3、企业微信'; +COMMENT ON COLUMN er_notify_config.notify_attribute IS '配置属性'; +COMMENT ON COLUMN er_notify_config.notify_threshold IS '通知阈值'; +COMMENT ON COLUMN er_notify_config.notify_scene IS '通知场景'; +COMMENT ON COLUMN er_notify_config.rate_limiter_status IS '限流状态 0、未启用 1、启用'; +COMMENT ON COLUMN er_notify_config.rate_limiter_threshold IS '每秒限流阈值'; +COMMENT ON COLUMN er_notify_config.description IS '描述'; +COMMENT ON COLUMN er_notify_config.create_dt IS '创建时间'; +COMMENT ON COLUMN er_notify_config.update_dt IS '修改时间'; +COMMENT ON TABLE er_notify_config IS '通知配置'; + + +CREATE TABLE er_retry_dead_letter_0 +( + id BIGSERIAL PRIMARY KEY, + unique_id VARCHAR(64) NOT NULL, + namespace_id VARCHAR(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR(64) NOT NULL, + scene_name VARCHAR(64) NOT NULL, + idempotent_id VARCHAR(64) NOT NULL, + biz_no VARCHAR(64) NOT NULL DEFAULT '', + executor_name VARCHAR(512) NOT NULL DEFAULT '', + args_str TEXT NOT NULL, + ext_attrs TEXT NOT NULL, + task_type SMALLINT NOT NULL DEFAULT 1, + create_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_namespace_id_group_name_unique_id_retry_dead_letter ON er_retry_dead_letter_0 (namespace_id, group_name, unique_id); +CREATE INDEX idx_namespace_id_group_name_scene_name_retry_dead_letter ON er_retry_dead_letter_0 (namespace_id, group_name, scene_name); +CREATE INDEX idx_idempotent_id_retry_dead_letter ON er_retry_dead_letter_0 (idempotent_id); +CREATE INDEX idx_biz_no_retry_dead_letter ON er_retry_dead_letter_0 (biz_no); +CREATE INDEX idx_create_dt_retry_dead_letter ON er_retry_dead_letter_0 (create_dt); + +COMMENT ON COLUMN er_retry_dead_letter_0.id IS '主键'; +COMMENT ON COLUMN er_retry_dead_letter_0.unique_id IS '同组下id唯一'; +COMMENT ON COLUMN er_retry_dead_letter_0.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_retry_dead_letter_0.group_name IS '组名称'; +COMMENT ON COLUMN er_retry_dead_letter_0.scene_name IS '场景名称'; +COMMENT ON COLUMN er_retry_dead_letter_0.idempotent_id IS '幂等id'; +COMMENT ON COLUMN er_retry_dead_letter_0.biz_no IS '业务编号'; +COMMENT ON COLUMN er_retry_dead_letter_0.executor_name IS '执行器名称'; +COMMENT ON COLUMN er_retry_dead_letter_0.args_str IS '执行方法参数'; +COMMENT ON COLUMN er_retry_dead_letter_0.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN er_retry_dead_letter_0.task_type IS '任务类型 1、重试数据 2、回调数据'; +COMMENT ON COLUMN er_retry_dead_letter_0.create_dt IS '创建时间'; +COMMENT ON TABLE er_retry_dead_letter_0 IS '死信队列表'; + +CREATE TABLE er_retry_task_0 +( + id BIGSERIAL PRIMARY KEY, + unique_id VARCHAR(64) NOT NULL, + namespace_id VARCHAR(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR(64) NOT NULL, + scene_name VARCHAR(64) NOT NULL, + idempotent_id VARCHAR(64) NOT NULL, + biz_no VARCHAR(64) NOT NULL DEFAULT '', + executor_name VARCHAR(512) NOT NULL DEFAULT '', + args_str TEXT NOT NULL, + ext_attrs TEXT NOT NULL, + next_trigger_at TIMESTAMP NOT NULL, + retry_count INT NOT NULL DEFAULT 0, + retry_status SMALLINT NOT NULL DEFAULT 0, + task_type SMALLINT NOT NULL DEFAULT 1, + create_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_name_unique_id_retry_task ON er_retry_task_0 (namespace_id, group_name, unique_id); +CREATE INDEX idx_namespace_id_group_name_scene_name_retry_task ON er_retry_task_0 (namespace_id, group_name, scene_name); +CREATE INDEX idx_namespace_id_group_name_retry_status_retry_task ON er_retry_task_0 (namespace_id, group_name, retry_status); +CREATE INDEX idx_idempotent_id_retry_task ON er_retry_task_0 (idempotent_id); +CREATE INDEX idx_biz_no_retry_task ON er_retry_task_0 (biz_no); +CREATE INDEX idx_create_dt_retry_task ON er_retry_task_0 (create_dt); + +COMMENT ON COLUMN er_retry_task_0.id IS '主键'; +COMMENT ON COLUMN er_retry_task_0.unique_id IS '同组下id唯一'; +COMMENT ON COLUMN er_retry_task_0.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_retry_task_0.group_name IS '组名称'; +COMMENT ON COLUMN er_retry_task_0.scene_name IS '场景名称'; +COMMENT ON COLUMN er_retry_task_0.idempotent_id IS '幂等id'; +COMMENT ON COLUMN er_retry_task_0.biz_no IS '业务编号'; +COMMENT ON COLUMN er_retry_task_0.executor_name IS '执行器名称'; +COMMENT ON COLUMN er_retry_task_0.args_str IS '执行方法参数'; +COMMENT ON COLUMN er_retry_task_0.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN er_retry_task_0.next_trigger_at IS '下次触发时间'; +COMMENT ON COLUMN er_retry_task_0.retry_count IS '重试次数'; +COMMENT ON COLUMN er_retry_task_0.retry_status IS '重试状态 0、重试中 1、成功 2、最大重试次数'; +COMMENT ON COLUMN er_retry_task_0.task_type IS '任务类型 1、重试数据 2、回调数据'; +COMMENT ON COLUMN er_retry_task_0.create_dt IS '创建时间'; +COMMENT ON COLUMN er_retry_task_0.update_dt IS '修改时间'; +COMMENT ON TABLE er_retry_task_0 IS '任务表'; + +CREATE TABLE er_retry_task_log +( + id BIGSERIAL PRIMARY KEY, + unique_id VARCHAR(64) NOT NULL, + namespace_id VARCHAR(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR(64) NOT NULL, + scene_name VARCHAR(64) NOT NULL, + idempotent_id VARCHAR(64) NOT NULL, + biz_no VARCHAR(64) NOT NULL DEFAULT '', + executor_name VARCHAR(512) NOT NULL DEFAULT '', + args_str TEXT NOT NULL, + ext_attrs TEXT NOT NULL, + retry_status SMALLINT NOT NULL DEFAULT 0, + task_type SMALLINT NOT NULL DEFAULT 1, + create_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP + +); + +CREATE INDEX idx_group_name_scene_name_retry_task_log ON er_retry_task_log (namespace_id, group_name, scene_name); +CREATE INDEX idx_retry_status_retry_task_log ON er_retry_task_log (retry_status); +CREATE INDEX idx_idempotent_id_retry_task_log ON er_retry_task_log (idempotent_id); +CREATE INDEX idx_unique_id ON er_retry_task_log (namespace_id, group_name, unique_id); +CREATE INDEX idx_biz_no_retry_task_log ON er_retry_task_log (biz_no); +CREATE INDEX idx_create_dt_retry_task_log ON er_retry_task_log (create_dt); + +COMMENT ON COLUMN er_retry_task_log.id IS '主键'; +COMMENT ON COLUMN er_retry_task_log.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_retry_task_log.unique_id IS '同组下id唯一'; +COMMENT ON COLUMN er_retry_task_log.group_name IS '组名称'; +COMMENT ON COLUMN er_retry_task_log.scene_name IS '场景名称'; +COMMENT ON COLUMN er_retry_task_log.idempotent_id IS '幂等id'; +COMMENT ON COLUMN er_retry_task_log.biz_no IS '业务编号'; +COMMENT ON COLUMN er_retry_task_log.executor_name IS '执行器名称'; +COMMENT ON COLUMN er_retry_task_log.args_str IS '执行方法参数'; +COMMENT ON COLUMN er_retry_task_log.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN er_retry_task_log.retry_status IS '重试状态 0、重试中 1、成功 2、最大次数'; +COMMENT ON COLUMN er_retry_task_log.task_type IS '任务类型 1、重试数据 2、回调数据'; +COMMENT ON COLUMN er_retry_task_log.create_dt IS '创建时间'; +COMMENT ON COLUMN er_retry_task_log.update_dt IS '修改时间'; +COMMENT ON TABLE er_retry_task_log IS '任务日志基础信息表'; + +CREATE TABLE er_retry_task_log_message +( + id BIGSERIAL PRIMARY KEY, + namespace_id VARCHAR(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR(64) NOT NULL, + unique_id VARCHAR(64) NOT NULL, + create_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + message TEXT NOT NULL, + log_num INT NOT NULL DEFAULT 1, + real_time BIGINT NOT NULL DEFAULT 0 +); + +CREATE INDEX idx_namespace_id_group_name_unique_id ON er_retry_task_log_message (namespace_id, group_name, unique_id); +CREATE INDEX idx_create_dt ON er_retry_task_log_message (create_dt); +COMMENT ON COLUMN er_retry_task_log_message.id IS '主键'; +COMMENT ON COLUMN er_retry_task_log_message.namespace_id IS '命名空间'; +COMMENT ON COLUMN er_retry_task_log_message.group_name IS '组名称'; +COMMENT ON COLUMN er_retry_task_log_message.unique_id IS '同组下id唯一'; +COMMENT ON COLUMN er_retry_task_log_message.create_dt IS '创建时间'; +COMMENT ON COLUMN er_retry_task_log_message.message IS '异常信息'; +COMMENT ON COLUMN er_retry_task_log_message.log_num IS '日志条数'; +COMMENT ON COLUMN er_retry_task_log_message.real_time IS '实际时间'; +COMMENT ON TABLE er_retry_task_log_message IS '任务调度日志信息记录表'; + +CREATE TABLE er_scene_config +( + id BIGSERIAL PRIMARY KEY, + namespace_id VARCHAR(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + scene_name VARCHAR(64) NOT NULL, + group_name VARCHAR(64) NOT NULL, + scene_status SMALLINT NOT NULL DEFAULT 0, + max_retry_count INT NOT NULL DEFAULT 5, + back_off SMALLINT NOT NULL DEFAULT 1, + trigger_interval VARCHAR(16) NOT NULL DEFAULT '', + deadline_request BIGINT NOT NULL DEFAULT 60000, + route_key SMALLINT NOT NULL DEFAULT 4, + executor_timeout INT NOT NULL DEFAULT 5, + description VARCHAR(256) NOT NULL DEFAULT '', + create_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_namespace_id_group_name_scene_name ON er_scene_config (namespace_id, group_name, scene_name); +COMMENT ON COLUMN er_scene_config.id IS '主键'; +COMMENT ON COLUMN er_scene_config.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_scene_config.scene_name IS '场景名称'; +COMMENT ON COLUMN er_scene_config.group_name IS '组名称'; +COMMENT ON COLUMN er_scene_config.scene_status IS '组状态 0、未启用 1、启用'; +COMMENT ON COLUMN er_scene_config.max_retry_count IS '最大重试次数'; +COMMENT ON COLUMN er_scene_config.back_off IS '1、默认等级 2、固定间隔时间 3、CRON 表达式'; +COMMENT ON COLUMN er_scene_config.trigger_interval IS '间隔时长'; +COMMENT ON COLUMN er_scene_config.deadline_request IS 'Deadline Request 调用链超时 单位毫秒'; +COMMENT ON COLUMN er_scene_config.description IS '描述'; +COMMENT ON COLUMN er_scene_config.route_key IS '路由策略'; +COMMENT ON COLUMN er_scene_config.executor_timeout IS '超时时间'; +COMMENT ON COLUMN er_scene_config.create_dt IS '创建时间'; +COMMENT ON COLUMN er_scene_config.update_dt IS '修改时间'; +COMMENT ON TABLE er_scene_config IS '场景配置'; + +CREATE TABLE er_server_node +( + id BIGSERIAL PRIMARY KEY, + namespace_id VARCHAR(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR(64) NOT NULL, + host_id VARCHAR(64) NOT NULL, + host_ip VARCHAR(64) NOT NULL, + context_path VARCHAR(256) NOT NULL DEFAULT '/', + host_port INT NOT NULL, + expire_at TIMESTAMP NOT NULL, + node_type SMALLINT NOT NULL, + ext_attrs VARCHAR(256) DEFAULT '', + create_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_host_id_host_ip ON er_server_node (host_id, host_ip); +CREATE INDEX idx_expire_at_node_type ON er_server_node (expire_at, node_type); +CREATE INDEX idx_namespace_id_group_name_server_node ON er_server_node (namespace_id, group_name); + +COMMENT ON COLUMN er_server_node.id IS '主键'; +COMMENT ON COLUMN er_server_node.group_name IS '组名称'; +COMMENT ON COLUMN er_server_node.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_server_node.host_id IS '主机id'; +COMMENT ON COLUMN er_server_node.host_ip IS '机器ip'; +COMMENT ON COLUMN er_server_node.context_path IS '客户端上下文路径 server.servlet.context-path'; +COMMENT ON COLUMN er_server_node.host_port IS '机器端口'; +COMMENT ON COLUMN er_server_node.expire_at IS '过期时间'; +COMMENT ON COLUMN er_server_node.node_type IS '节点类型 1、客户端 2、是服务端'; +COMMENT ON COLUMN er_server_node.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN er_server_node.create_dt IS '创建时间'; +COMMENT ON COLUMN er_server_node.update_dt IS '修改时间'; +COMMENT ON TABLE er_server_node IS '服务器节点'; + +CREATE TABLE er_distributed_lock +( + id BIGSERIAL PRIMARY KEY, + name VARCHAR(64) NOT NULL, + lock_until TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + locked_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + locked_by VARCHAR(255) NOT NULL, + create_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +ALTER TABLE er_distributed_lock + ADD CONSTRAINT uk_name UNIQUE (name); + +COMMENT ON COLUMN er_distributed_lock.id IS '主键'; +COMMENT ON COLUMN er_distributed_lock.name IS '锁名称'; +COMMENT ON COLUMN er_distributed_lock.lock_until IS '锁定时长'; +COMMENT ON COLUMN er_distributed_lock.locked_at IS '锁定时间'; +COMMENT ON COLUMN er_distributed_lock.locked_by IS '锁定者'; +COMMENT ON COLUMN er_distributed_lock.create_dt IS '创建时间'; +COMMENT ON COLUMN er_distributed_lock.update_dt IS '修改时间'; +COMMENT ON TABLE er_distributed_lock IS '锁定表'; + + +CREATE TABLE er_system_user +( + id BIGSERIAL PRIMARY KEY, + username VARCHAR(64) NOT NULL, + password VARCHAR(128) NOT NULL, + role SMALLINT NOT NULL DEFAULT 0, + create_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_username ON er_system_user (username); +COMMENT ON COLUMN er_system_user.id IS '主键'; +COMMENT ON COLUMN er_system_user.username IS '账号'; +COMMENT ON COLUMN er_system_user.password IS '密码'; +COMMENT ON COLUMN er_system_user.role IS '角色:1-普通用户、2-管理员'; +COMMENT ON COLUMN er_system_user.create_dt IS '创建时间'; +COMMENT ON COLUMN er_system_user.update_dt IS '修改时间'; +COMMENT ON TABLE er_system_user IS '系统用户表'; + +-- pwd: admin +INSERT INTO er_system_user VALUES (1, 'admin', '465c194afb65670f38322df087f0a9bb225cc257e43eb4ac5a0c98ef5b3173ac', 2, now(), now()); + +CREATE TABLE er_system_user_permission +( + id BIGSERIAL PRIMARY KEY, + namespace_id VARCHAR(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR(64) NOT NULL, + system_user_id BIGINT NOT NULL, + create_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_namespace_id_group_name_system_user_id ON er_system_user_permission (namespace_id, group_name, system_user_id); +COMMENT ON COLUMN er_system_user_permission.id IS '主键'; +COMMENT ON COLUMN er_system_user_permission.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_system_user_permission.group_name IS '组名称'; +COMMENT ON COLUMN er_system_user_permission.system_user_id IS '系统用户id'; +COMMENT ON COLUMN er_system_user_permission.create_dt IS '创建时间'; +COMMENT ON COLUMN er_system_user_permission.update_dt IS '修改时间'; +COMMENT ON TABLE er_system_user_permission IS '系统用户权限表'; + + +CREATE TABLE er_sequence_alloc +( + id BIGSERIAL PRIMARY KEY, + namespace_id VARCHAR(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR(64) NOT NULL DEFAULT '', + max_id BIGINT NOT NULL DEFAULT 1, + step INT NOT NULL DEFAULT 100, + update_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_namespace_id_group_name ON er_sequence_alloc (namespace_id, group_name); + +COMMENT ON COLUMN er_sequence_alloc.id IS '主键'; +COMMENT ON COLUMN er_sequence_alloc.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_sequence_alloc.group_name IS '组名称'; +COMMENT ON COLUMN er_sequence_alloc.max_id IS '最大id'; +COMMENT ON COLUMN er_sequence_alloc.step IS '步长'; +COMMENT ON COLUMN er_sequence_alloc.update_dt IS '更新时间'; +COMMENT ON TABLE er_sequence_alloc IS '号段模式序号ID分配表'; + +-- 分布式调度DDL +CREATE TABLE er_job +( + id BIGSERIAL PRIMARY KEY, + namespace_id VARCHAR(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR(64) NOT NULL, + job_name VARCHAR(64) NOT NULL, + args_str TEXT NOT NULL DEFAULT '', + args_type SMALLINT NOT NULL DEFAULT 1, + next_trigger_at BIGINT NOT NULL, + job_status SMALLINT NOT NULL DEFAULT 1, + task_type SMALLINT NOT NULL DEFAULT 1, + route_key SMALLINT NOT NULL DEFAULT 4, + executor_type SMALLINT NOT NULL DEFAULT 1, + executor_info VARCHAR(255) DEFAULT NULL, + trigger_type SMALLINT NOT NULL, + trigger_interval VARCHAR(255) NOT NULL, + block_strategy SMALLINT NOT NULL DEFAULT 1, + executor_timeout INT NOT NULL DEFAULT 0, + max_retry_times INT NOT NULL DEFAULT 0, + parallel_num INT NOT NULL DEFAULT 1, + retry_interval INT NOT NULL DEFAULT 0, + bucket_index INT NOT NULL DEFAULT 0, + resident SMALLINT NOT NULL DEFAULT 0, + description VARCHAR(256) NOT NULL DEFAULT '', + ext_attrs VARCHAR(256) DEFAULT NULL, + create_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted SMALLINT NOT NULL DEFAULT 0 +); + +CREATE INDEX idx_namespace_id_group_name_job ON er_job (namespace_id, group_name); +CREATE INDEX idx_job_status_bucket_index_job ON er_job (job_status, bucket_index); +CREATE INDEX idx_create_dt_job ON er_job (create_dt); + +COMMENT ON COLUMN er_job.id IS '主键'; +COMMENT ON COLUMN er_job.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_job.group_name IS '组名称'; +COMMENT ON COLUMN er_job.job_name IS '名称'; +COMMENT ON COLUMN er_job.args_str IS '执行方法参数'; +COMMENT ON COLUMN er_job.args_type IS '参数类型'; +COMMENT ON COLUMN er_job.next_trigger_at IS '下次触发时间'; +COMMENT ON COLUMN er_job.job_status IS '重试状态 0、关闭、1、开启'; +COMMENT ON COLUMN er_job.task_type IS '任务类型 1、集群 2、广播 3、切片'; +COMMENT ON COLUMN er_job.route_key IS '路由策略'; +COMMENT ON COLUMN er_job.executor_type IS '执行器类型'; +COMMENT ON COLUMN er_job.executor_info IS '执行器名称'; +COMMENT ON COLUMN er_job.trigger_type IS '触发类型 1.CRON 表达式 2. 固定时间'; +COMMENT ON COLUMN er_job.trigger_interval IS '间隔时长'; +COMMENT ON COLUMN er_job.block_strategy IS '阻塞策略 1、丢弃 2、覆盖 3、并行'; +COMMENT ON COLUMN er_job.executor_timeout IS '任务执行超时时间,单位秒'; +COMMENT ON COLUMN er_job.max_retry_times IS '最大重试次数'; +COMMENT ON COLUMN er_job.parallel_num IS '并行数'; +COMMENT ON COLUMN er_job.retry_interval IS '更新重试间隔(s)'; +COMMENT ON COLUMN er_job.bucket_index IS 'bucket'; +COMMENT ON COLUMN er_job.resident IS '是否是常驻任务'; +COMMENT ON COLUMN er_job.description IS '描述'; +COMMENT ON COLUMN er_job.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN er_job.create_dt IS '创建时间'; +COMMENT ON COLUMN er_job.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN er_job.update_dt IS '更新时间'; +COMMENT ON TABLE er_job IS '任务信息'; + +CREATE TABLE er_job_log_message +( + id BIGSERIAL PRIMARY KEY, + namespace_id VARCHAR(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR(64) NOT NULL, + job_id BIGINT NOT NULL, + task_batch_id BIGINT NOT NULL, + task_id BIGINT NOT NULL, + message TEXT NOT NULL, + log_num INT NOT NULL DEFAULT 1, + real_time BIGINT NOT NULL DEFAULT 0, + ext_attrs VARCHAR(256) DEFAULT '', + create_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_namespace_id_group_name_to_job_log_message ON er_job_log_message (namespace_id, group_name); +CREATE INDEX idx_task_batch_id_task_id_to_job_log_message ON er_job_log_message (task_batch_id, task_id); +CREATE INDEX idx_create_dt_to_job_log_message ON er_job_log_message (create_dt); + +COMMENT ON COLUMN er_job_log_message.id IS '主键'; +COMMENT ON COLUMN er_job_log_message.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_job_log_message.group_name IS '组名称'; +COMMENT ON COLUMN er_job_log_message.job_id IS '任务信息id'; +COMMENT ON COLUMN er_job_log_message.task_batch_id IS '任务批次id'; +COMMENT ON COLUMN er_job_log_message.task_id IS '调度任务id'; +COMMENT ON COLUMN er_job_log_message.message IS '调度信息'; +COMMENT ON COLUMN er_job_log_message.log_num IS '日志序号'; +COMMENT ON COLUMN er_job_log_message.real_time IS '实际时间'; +COMMENT ON COLUMN er_job_log_message.create_dt IS '创建时间'; +COMMENT ON COLUMN er_job_log_message.ext_attrs IS '扩展字段'; +COMMENT ON TABLE er_job_log_message IS '调度日志'; + +CREATE TABLE er_job_task +( + id BIGSERIAL PRIMARY KEY, + namespace_id VARCHAR(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR(64) NOT NULL, + job_id BIGINT NOT NULL, + task_batch_id BIGINT NOT NULL, + parent_id BIGINT NOT NULL DEFAULT 0, + task_status SMALLINT NOT NULL DEFAULT 0, + retry_count INT NOT NULL DEFAULT 0, + client_info VARCHAR(128) DEFAULT NULL, + result_message TEXT NOT NULL, + args_str TEXT NOT NULL, + args_type SMALLINT NOT NULL DEFAULT 1, + ext_attrs VARCHAR(256) DEFAULT '', + create_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + + +CREATE INDEX idx_namespace_id_group_name_to_job_task ON er_job_task (namespace_id, group_name); +CREATE INDEX idx_task_batch_id_task_status_to_job_task ON er_job_task (task_batch_id, task_status); +CREATE INDEX idx_create_dt_to_job_task ON er_job_task (create_dt); +COMMENT ON COLUMN er_job_task.id IS '主键'; +COMMENT ON COLUMN er_job_task.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_job_task.group_name IS '组名称'; +COMMENT ON COLUMN er_job_task.job_id IS '任务信息id'; +COMMENT ON COLUMN er_job_task.task_batch_id IS '任务批次id'; +COMMENT ON COLUMN er_job_task.parent_id IS '父执行器id'; +COMMENT ON COLUMN er_job_task.task_status IS '执行的状态 0、失败 1、成功'; +COMMENT ON COLUMN er_job_task.retry_count IS '重试次数'; +COMMENT ON COLUMN er_job_task.client_info IS '客户端地址 clientId#ip:port'; +COMMENT ON COLUMN er_job_task.result_message IS '调度信息'; +COMMENT ON COLUMN er_job_task.args_str IS '执行方法参数'; +COMMENT ON COLUMN er_job_task.args_type IS '参数类型'; +COMMENT ON COLUMN er_job_task.create_dt IS '创建时间'; +COMMENT ON COLUMN er_job_task.update_dt IS '创建时间'; +COMMENT ON COLUMN er_job_task.ext_attrs IS '扩展字段'; +COMMENT ON TABLE er_job_task IS '任务实例'; + +CREATE TABLE er_job_task_batch +( + id BIGSERIAL PRIMARY KEY, + namespace_id VARCHAR(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR(64) NOT NULL, + job_id BIGINT NOT NULL, + workflow_node_id BIGINT NOT NULL DEFAULT 0, + parent_workflow_node_id BIGINT NOT NULL DEFAULT 0, + workflow_task_batch_id BIGINT NOT NULL DEFAULT 0, + parent_id VARCHAR(64) NOT NULL DEFAULT '', + task_batch_status SMALLINT NOT NULL DEFAULT 0, + operation_reason SMALLINT NOT NULL DEFAULT 0, + execution_at BIGINT NOT NULL DEFAULT 0, + system_task_type SMALLINT NOT NULL DEFAULT 3, + ext_attrs VARCHAR(256) DEFAULT '', + deleted SMALLINT NOT NULL DEFAULT 0, + create_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_namespace_id_group_name_to_job_task_batch ON er_job_task_batch (namespace_id, group_name); +CREATE INDEX idx_job_id_task_batch_status_to_job_task_batch ON er_job_task_batch (job_id, task_batch_status); +CREATE INDEX idx_create_dt_to_job_task_batch ON er_job_task_batch (create_dt); +CREATE INDEX idx_workflow_task_batch_id_workflow_node_id ON er_job_task_batch (workflow_task_batch_id, workflow_node_id); + +COMMENT ON COLUMN er_job_task_batch.id IS '主键'; +COMMENT ON COLUMN er_job_task_batch.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_job_task_batch.group_name IS '组名称'; +COMMENT ON COLUMN er_job_task_batch.job_id IS '任务信息id'; +COMMENT ON COLUMN er_job_task_batch.task_batch_status IS '任务批次状态 0、失败 1、成功'; +COMMENT ON COLUMN er_job_task_batch.operation_reason IS '操作原因'; +COMMENT ON COLUMN er_job_task_batch.workflow_node_id IS '工作流节点id'; +COMMENT ON COLUMN er_job_task_batch.parent_workflow_node_id IS '父节点'; +COMMENT ON COLUMN er_job_task_batch.workflow_task_batch_id IS '任务批次id'; +COMMENT ON COLUMN er_job_task_batch.system_task_type IS '任务类型 0、系统任务 1、业务任务'; +COMMENT ON COLUMN er_job_task_batch.execution_at IS '任务执行时间'; +COMMENT ON COLUMN er_job_task_batch.parent_id IS '父节点'; +COMMENT ON COLUMN er_job_task_batch.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN er_job_task_batch.create_dt IS '创建时间'; +COMMENT ON COLUMN er_job_task_batch.update_dt IS '创建时间'; +COMMENT ON COLUMN er_job_task_batch.ext_attrs IS '扩展字段'; +COMMENT ON TABLE er_job_task_batch IS '任务批次'; + +CREATE TABLE er_job_notify_config +( + id BIGSERIAL PRIMARY KEY, + namespace_id VARCHAR(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR(64) NOT NULL, + job_id BIGINT NOT NULL, + notify_status SMALLINT NOT NULL DEFAULT 0, + notify_type SMALLINT NOT NULL DEFAULT 0, + notify_attribute VARCHAR(512) NOT NULL, + notify_threshold INT NOT NULL DEFAULT 0, + notify_scene SMALLINT NOT NULL DEFAULT 0, + rate_limiter_status SMALLINT NOT NULL DEFAULT 0, + rate_limiter_threshold INT NOT NULL DEFAULT 0, + description VARCHAR(256) NOT NULL DEFAULT '', + create_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_namespace_id_group_name_job_id_job_notify_config ON er_job_notify_config (namespace_id, group_name, job_id); + +COMMENT ON COLUMN er_job_notify_config.id IS '主键'; +COMMENT ON COLUMN er_job_notify_config.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_job_notify_config.group_name IS '组名称'; +COMMENT ON COLUMN er_job_notify_config.job_id IS '任务信息id'; +COMMENT ON COLUMN er_job_notify_config.notify_status IS '通知状态 0、未启用 1、启用'; +COMMENT ON COLUMN er_job_notify_config.notify_type IS '通知类型 1、钉钉 2、邮件 3、企业微信'; +COMMENT ON COLUMN er_job_notify_config.notify_attribute IS '配置属性'; +COMMENT ON COLUMN er_job_notify_config.notify_threshold IS '通知阈值'; +COMMENT ON COLUMN er_job_notify_config.notify_scene IS '通知场景'; +COMMENT ON COLUMN er_job_notify_config.rate_limiter_status IS '限流状态 0、未启用 1、启用'; +COMMENT ON COLUMN er_job_notify_config.rate_limiter_threshold IS '每秒限流阈值'; +COMMENT ON COLUMN er_job_notify_config.description IS '描述'; +COMMENT ON COLUMN er_job_notify_config.create_dt IS '创建时间'; +COMMENT ON COLUMN er_job_notify_config.update_dt IS '修改时间'; +COMMENT ON TABLE er_job_notify_config IS '通知配置'; + +CREATE TABLE er_retry_summary +( + id BIGSERIAL PRIMARY KEY, + namespace_id VARCHAR(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR(64) NOT NULL DEFAULT '', + scene_name VARCHAR(50) NOT NULL DEFAULT '', + trigger_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + running_num INT NOT NULL DEFAULT 0, + finish_num INT NOT NULL DEFAULT 0, + max_count_num INT NOT NULL DEFAULT 0, + suspend_num INT NOT NULL DEFAULT 0, + create_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_scene_name_trigger_at ON er_retry_summary (namespace_id, group_name, scene_name, trigger_at); + +COMMENT ON COLUMN er_retry_summary.id IS '主键'; +COMMENT ON COLUMN er_retry_summary.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_retry_summary.group_name IS '组名称'; +COMMENT ON COLUMN er_retry_summary.scene_name IS '场景名称'; +COMMENT ON COLUMN er_retry_summary.trigger_at IS '统计时间'; +COMMENT ON COLUMN er_retry_summary.running_num IS '重试中-日志数量'; +COMMENT ON COLUMN er_retry_summary.finish_num IS '重试完成-日志数量'; +COMMENT ON COLUMN er_retry_summary.max_count_num IS '重试到达最大次数-日志数量'; +COMMENT ON COLUMN er_retry_summary.suspend_num IS '暂停重试-日志数量'; +COMMENT ON COLUMN er_retry_summary.create_dt IS '创建时间'; +COMMENT ON COLUMN er_retry_summary.update_dt IS '修改时间'; +COMMENT ON TABLE er_retry_summary IS 'DashBoard_Retry'; + +CREATE TABLE er_job_summary +( + id BIGSERIAL PRIMARY KEY, + namespace_id VARCHAR(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR(64) NOT NULL DEFAULT '', + business_id BIGINT NOT NULL, + system_task_type SMALLINT NOT NULL DEFAULT '3', + trigger_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + success_num INT NOT NULL DEFAULT 0, + fail_num INT NOT NULL DEFAULT 0, + fail_reason VARCHAR(512) NOT NULL DEFAULT '', + stop_num INT NOT NULL DEFAULT 0, + stop_reason VARCHAR(512) NOT NULL DEFAULT '', + cancel_num INT NOT NULL DEFAULT 0, + cancel_reason VARCHAR(512) NOT NULL DEFAULT '', + create_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_trigger_at_system_task_type_business_id ON er_job_summary (trigger_at, system_task_type, business_id); +CREATE INDEX idx_namespace_id_group_name_job_id ON er_job_summary (namespace_id, group_name, business_id); + +COMMENT ON COLUMN er_job_summary.id IS '主键'; +COMMENT ON COLUMN er_job_summary.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_job_summary.group_name IS '组名称'; +COMMENT ON COLUMN er_job_summary.business_id IS '业务id (job_id或workflow_id)'; +COMMENT ON COLUMN er_job_summary.system_task_type IS '任务类型 3、JOB任务 4、WORKFLOW任务'; +COMMENT ON COLUMN er_job_summary.trigger_at IS '统计时间'; +COMMENT ON COLUMN er_job_summary.success_num IS '执行成功-日志数量'; +COMMENT ON COLUMN er_job_summary.fail_num IS '执行失败-日志数量'; +COMMENT ON COLUMN er_job_summary.fail_reason IS '失败原因'; +COMMENT ON COLUMN er_job_summary.stop_num IS '执行失败-日志数量'; +COMMENT ON COLUMN er_job_summary.stop_reason IS '失败原因'; +COMMENT ON COLUMN er_job_summary.cancel_num IS '执行失败-日志数量'; +COMMENT ON COLUMN er_job_summary.cancel_reason IS '失败原因'; +COMMENT ON TABLE er_job_summary IS 'DashBoard_Job'; + +CREATE TABLE er_workflow +( + id BIGSERIAL PRIMARY KEY, + workflow_name varchar(64) NOT NULL, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL, + workflow_status smallint NOT NULL DEFAULT 1, + trigger_type smallint NOT NULL, + trigger_interval varchar(255) NOT NULL, + next_trigger_at BIGINT NOT NULL, + block_strategy smallint NOT NULL DEFAULT 1, + executor_timeout INT NOT NULL DEFAULT 0, + description varchar(256) NOT NULL DEFAULT '', + flow_info text DEFAULT NULL, + bucket_index INT NOT NULL DEFAULT 0, + version INT NOT NULL, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted smallint NOT NULL DEFAULT 0, + ext_attrs varchar(256) NULL DEFAULT '' +); + + +CREATE INDEX idx_create_dt_workflow ON er_workflow (create_dt); +CREATE INDEX idx_namespace_id_group_name_workflow ON er_workflow (namespace_id, group_name); + +COMMENT ON TABLE er_workflow IS '工作流'; +COMMENT ON COLUMN er_workflow.id IS '主键'; +COMMENT ON COLUMN er_workflow.workflow_name IS '工作流名称'; +COMMENT ON COLUMN er_workflow.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_workflow.group_name IS '组名称'; +COMMENT ON COLUMN er_workflow.workflow_status IS '工作流状态 0、关闭、1、开启'; +COMMENT ON COLUMN er_workflow.trigger_type IS '触发类型 1.CRON 表达式 2. 固定时间'; +COMMENT ON COLUMN er_workflow.trigger_interval IS '间隔时长'; +COMMENT ON COLUMN er_workflow.next_trigger_at IS '下次触发时间'; +COMMENT ON COLUMN er_workflow.block_strategy IS '阻塞策略 1、丢弃 2、覆盖 3、并行'; +COMMENT ON COLUMN er_workflow.executor_timeout IS '任务执行超时时间,单位秒'; +COMMENT ON COLUMN er_workflow.description IS '描述'; +COMMENT ON COLUMN er_workflow.flow_info IS '流程信息'; +COMMENT ON COLUMN er_workflow.bucket_index IS 'bucket'; +COMMENT ON COLUMN er_workflow.version IS '版本号'; +COMMENT ON COLUMN er_workflow.create_dt IS '创建时间'; +COMMENT ON COLUMN er_workflow.update_dt IS '修改时间'; +COMMENT ON COLUMN er_workflow.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN er_workflow.ext_attrs IS '扩展字段'; + +CREATE TABLE er_workflow_node +( + id BIGSERIAL PRIMARY KEY, + namespace_id VARCHAR(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + node_name VARCHAR(64) NOT NULL, + group_name VARCHAR(64) NOT NULL, + job_id BIGINT NOT NULL, + workflow_id BIGINT NOT NULL, + node_type SMALLINT NOT NULL DEFAULT 1, + expression_type SMALLINT NOT NULL DEFAULT 0, + fail_strategy SMALLINT NOT NULL DEFAULT 1, + workflow_node_status SMALLINT NOT NULL DEFAULT 1, + priority_level INT NOT NULL DEFAULT 1, + node_info TEXT DEFAULT NULL, + version INT NOT NULL, + create_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted SMALLINT NOT NULL DEFAULT 0, + ext_attrs VARCHAR(256) NULL DEFAULT '' +); + +CREATE INDEX idx_create_dt_workflow_node ON er_workflow_node (create_dt); +CREATE INDEX idx_namespace_id_group_name_workflow_node ON er_workflow_node (namespace_id, group_name); + +COMMENT ON TABLE er_workflow_node IS '工作流节点'; +COMMENT ON COLUMN er_workflow_node.id IS '主键'; +COMMENT ON COLUMN er_workflow_node.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_workflow_node.node_name IS '节点名称'; +COMMENT ON COLUMN er_workflow_node.group_name IS '组名称'; +COMMENT ON COLUMN er_workflow_node.job_id IS '任务信息id'; +COMMENT ON COLUMN er_workflow_node.workflow_id IS '工作流ID'; +COMMENT ON COLUMN er_workflow_node.node_type IS '1、任务节点 2、条件节点'; +COMMENT ON COLUMN er_workflow_node.expression_type IS '1、SpEl、2、Aviator 3、QL'; +COMMENT ON COLUMN er_workflow_node.fail_strategy IS '失败策略 1、跳过 2、阻塞'; +COMMENT ON COLUMN er_workflow_node.workflow_node_status IS '工作流节点状态 0、关闭、1、开启'; +COMMENT ON COLUMN er_workflow_node.priority_level IS '优先级'; +COMMENT ON COLUMN er_workflow_node.node_info IS '节点信息'; +COMMENT ON COLUMN er_workflow_node.version IS '版本号'; +COMMENT ON COLUMN er_workflow_node.create_dt IS '创建时间'; +COMMENT ON COLUMN er_workflow_node.update_dt IS '修改时间'; +COMMENT ON COLUMN er_workflow_node.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN er_workflow_node.ext_attrs IS '扩展字段'; + +CREATE TABLE er_workflow_task_batch +( + id BIGSERIAL PRIMARY KEY, + namespace_id VARCHAR(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name VARCHAR(64) NOT NULL, + workflow_id BIGINT NOT NULL, + task_batch_status SMALLINT NOT NULL DEFAULT 0, + operation_reason SMALLINT NOT NULL DEFAULT 0, + flow_info TEXT DEFAULT NULL, + execution_at BIGINT NOT NULL DEFAULT 0, + create_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted SMALLINT NOT NULL DEFAULT 0, + ext_attrs VARCHAR(256) NULL DEFAULT '' +); + +CREATE INDEX idx_job_id_task_batch_status_workflow_task_batch ON er_workflow_task_batch (workflow_id, task_batch_status); +CREATE INDEX idx_create_dt_workflow_task_batch ON er_workflow_task_batch (create_dt); +CREATE INDEX idx_namespace_id_group_name_workflow_task_batch ON er_workflow_task_batch (namespace_id, group_name); + +COMMENT ON TABLE er_workflow_task_batch IS '工作流批次'; +COMMENT ON COLUMN er_workflow_task_batch.id IS '主键'; +COMMENT ON COLUMN er_workflow_task_batch.namespace_id IS '命名空间id'; +COMMENT ON COLUMN er_workflow_task_batch.group_name IS '组名称'; +COMMENT ON COLUMN er_workflow_task_batch.workflow_id IS '工作流任务id'; +COMMENT ON COLUMN er_workflow_task_batch.task_batch_status IS '任务批次状态 0、失败 1、成功'; +COMMENT ON COLUMN er_workflow_task_batch.operation_reason IS '操作原因'; +COMMENT ON COLUMN er_workflow_task_batch.flow_info IS '流程信息'; +COMMENT ON COLUMN er_workflow_task_batch.execution_at IS '任务执行时间'; +COMMENT ON COLUMN er_workflow_task_batch.create_dt IS '创建时间'; +COMMENT ON COLUMN er_workflow_task_batch.update_dt IS '修改时间'; +COMMENT ON COLUMN er_workflow_task_batch.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN er_workflow_task_batch.ext_attrs IS '扩展字段'; diff --git a/script/sql/postgres/flowable.sql b/script/sql/postgres/flowable.sql new file mode 100644 index 000000000..a44b051e7 --- /dev/null +++ b/script/sql/postgres/flowable.sql @@ -0,0 +1,341 @@ +insert into sys_menu values('11616', '工作流' , '0', '6', 'workflow', '', '', '1', '0', 'M', '0', '0', '', 'tree-table', 103, 1, now(), NULL, NULL, ''); +insert into sys_menu values('11617', '模型管理', '11616', '2', 'model', 'workflow/model/index', '', '1', '1', 'C', '0', '0', 'workflow:model:list', 'tree-table', 103, 1, now(), NULL, NULL, ''); +insert into sys_menu values('11618', '我的任务', '0', '7', 'task', '', '', '1', '0', 'M', '0', '0', '', 'tree-table', 103, 1, now(), NULL, NULL, ''); +insert into sys_menu values('11619', '我的待办', '11618', '2', 'taskWaiting', 'workflow/task/taskWaiting', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, now(), NULL, NULL, ''); +insert into sys_menu values('11632', '我的已办', '11618', '3', 'taskFinish', 'workflow/task/taskFinish', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, now(), NULL, NULL, ''); +insert into sys_menu values('11633', '我的抄送', '11618', '4', 'taskCopyList', 'workflow/task/taskCopyList', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, now(), NULL, NULL, ''); +insert into sys_menu values('11620', '流程定义', '11616', '3', 'processDefinition', 'workflow/processDefinition/index', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, now(), NULL, NULL, ''); +insert into sys_menu values('11621', '流程实例', '11630', '1', 'processInstance', 'workflow/processInstance/index', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, now(), NULL, NULL, ''); +insert into sys_menu values('11622', '流程分类', '11616', '1', 'category', 'workflow/category/index', '', '1', '0', 'C', '0', '0', 'workflow:category:list', 'tree-table', 103, 1, now(), NULL, NULL, ''); +insert into sys_menu values('11629', '我发起的', '11618', '1', 'myDocument', 'workflow/task/myDocument', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, now(), NULL, NULL, ''); +insert into sys_menu values('11630', '流程监控', '11616', '4', 'monitor', '', '', '1', '0', 'M', '0', '0', '', 'tree-table', 103, 1, now(), NULL, NULL, ''); +insert into sys_menu values('11631', '待办任务', '11630', '2', 'allTaskWaiting', 'workflow/task/allTaskWaiting', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, now(), NULL, NULL, ''); + + +-- 流程分类管理相关按钮 +insert into sys_menu values ('11623', '流程分类查询', '11622', '1', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values ('11624', '流程分类新增', '11622', '2', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:add', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values ('11625', '流程分类修改', '11622', '3', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:edit', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values ('11626', '流程分类删除', '11622', '4', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:remove','#', 103, 1, now(), null, null, ''); +insert into sys_menu values ('11627', '流程分类导出', '11622', '5', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:export','#', 103, 1, now(), null, null, ''); +-- 请假单信息 +create table test_leave +( + id bigint not null + constraint test_leave_pk + primary key, + leave_type varchar(255), + start_date timestamp, + end_date timestamp, + leave_days bigint, + remark varchar(255), + create_dept bigint, + create_by bigint, + create_time timestamp, + update_by bigint, + update_time timestamp, + tenant_id varchar(20) +); + +comment on table test_leave is '请假申请表'; + +comment on column test_leave.id is '主键'; + +comment on column test_leave.leave_type is '请假类型'; + +comment on column test_leave.start_date is '开始时间'; + +comment on column test_leave.end_date is '结束时间'; + +comment on column test_leave.remark is '请假原因'; + +comment on column test_leave.create_dept is '创建部门'; + +comment on column test_leave.create_by is '创建者'; + +comment on column test_leave.create_time is '创建时间'; + +comment on column test_leave.update_by is '更新者'; + +comment on column test_leave.update_time is '更新时间'; + +comment on column test_leave.tenant_id is '租户编码'; + +alter table test_leave + owner to postgres; + +-- 流程分类信息表 +create table wf_category +( + id bigint not null + constraint wf_category_pk + primary key, + category_name varchar(255), + category_code varchar(255), + parent_id bigint, + sort_num bigint, + tenant_id varchar(20), + create_dept bigint, + create_by bigint, + create_time timestamp, + update_by bigint, + update_time timestamp +); + +comment on table wf_category is '流程分类'; + +comment on column wf_category.id is '主键'; + +comment on column wf_category.category_name is '分类名称'; + +comment on column wf_category.category_code is '分类编码'; + +comment on column wf_category.parent_id is '父级id'; + +comment on column wf_category.sort_num is '排序'; + +comment on column wf_category.tenant_id is '租户id'; + +comment on column wf_category.create_dept is '创建部门'; + +comment on column wf_category.create_by is '创建者'; + +comment on column wf_category.create_time is '创建时间'; + +comment on column wf_category.update_by is '修改者'; + +comment on column wf_category.update_time is '修改时间'; + +alter table wf_category + owner to postgres; + +create unique index uni_category_code + on wf_category (category_code); + +INSERT INTO wf_category values (1, 'OA', 'OA', 0, 0, '000000', 103, 1, now(), 1, now()); + +create table wf_task_back_node +( + id bigint not null + constraint pk_wf_task_back_node + primary key, + node_id varchar(255) not null, + node_name varchar(255) not null, + order_no bigint not null, + instance_id varchar(255) not null, + task_type varchar(255) not null, + assignee varchar(2000) not null, + tenant_id varchar(20), + create_dept bigint, + create_by bigint, + create_time timestamp, + update_by bigint, + update_time timestamp +); + +comment on table wf_task_back_node is '节点审批记录'; + +comment on column wf_task_back_node.id is '主键'; + +comment on column wf_task_back_node.node_id is '节点id'; + +comment on column wf_task_back_node.node_name is '节点名称'; + +comment on column wf_task_back_node.order_no is '排序'; + +comment on column wf_task_back_node.instance_id is '流程实例id'; + +comment on column wf_task_back_node.task_type is '节点类型'; + +comment on column wf_task_back_node.assignee is '审批人'; + +comment on column wf_task_back_node.tenant_id is '租户id'; + +comment on column wf_task_back_node.create_dept is '创建部门'; + +comment on column wf_task_back_node.create_by is '创建者'; + +comment on column wf_task_back_node.create_time is '创建时间'; + +comment on column wf_task_back_node.update_by is '修改者'; + +comment on column wf_task_back_node.update_time is '修改时间'; + +alter table wf_task_back_node + owner to postgres; + +create table wf_definition_config +( + id bigint not null + constraint pk_wf_definition_config + primary key, + table_name varchar(255) not null, + definition_id varchar(255) not null, + process_key varchar(255) not null, + version bigint not null, + tenant_id varchar(20), + create_dept bigint, + create_by bigint, + create_time timestamp, + update_by bigint, + update_time timestamp +); + +comment on table wf_definition_config is '流程定义配置'; + +comment on column wf_definition_config.id is '主键'; + +comment on column wf_definition_config.table_name is '表名'; + +comment on column wf_definition_config.definition_id is '流程定义ID'; + +comment on column wf_definition_config.process_key is '流程KEY'; + +comment on column wf_definition_config.version is '流程版本'; + +comment on column wf_definition_config.tenant_id is '租户id'; + +comment on column wf_definition_config.create_dept is '创建部门'; + +comment on column wf_definition_config.create_by is '创建者'; + +comment on column wf_definition_config.create_time is '创建时间'; + +comment on column wf_definition_config.update_by is '修改者'; + +comment on column wf_definition_config.update_time is '修改时间'; + +alter table wf_definition_config + owner to postgres; +create unique index uni_definition_id + on wf_definition_config (definition_id); + +create table wf_form_manage +( + id bigint not null + constraint pk_wf_form_manage + primary key, + form_name varchar(255) not null, + form_type varchar(255) not null, + router varchar(255) not null, + remark varchar(500), + tenant_id varchar(20), + create_dept bigint, + create_by bigint, + create_time timestamp, + update_by bigint, + update_time timestamp +); + +comment on table wf_form_manage is '表单管理'; + +comment on column wf_form_manage.id is '主键'; + +comment on column wf_form_manage.form_name is '表单名称'; + +comment on column wf_form_manage.form_type is '表单类型'; + +comment on column wf_form_manage.router is '路由地址/表单ID'; + +comment on column wf_form_manage.remark is '备注'; + +comment on column wf_form_manage.tenant_id is '租户id'; + +comment on column wf_form_manage.create_dept is '创建部门'; + +comment on column wf_form_manage.create_by is '创建者'; + +comment on column wf_form_manage.create_time is '创建时间'; + +comment on column wf_form_manage.update_by is '修改者'; + +comment on column wf_form_manage.update_time is '修改时间'; + +insert into wf_form_manage(id, form_name, form_type, router, remark, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1, '请假申请', 'static', '/demo/leaveEdit/index', NULL, '000000', 103, 1, now(), 1, now()); + +create table wf_node_config +( + id bigint not null + constraint pk_wf_node_config + primary key, + form_id bigint, + form_type varchar(255), + node_name varchar(255) not null, + node_id varchar(255) not null, + definition_id varchar(255) not null, + apply_user_task char(1) default '0', + tenant_id varchar(20), + create_dept bigint, + create_by bigint, + create_time timestamp, + update_by bigint, + update_time timestamp +); + +comment on table wf_node_config is '节点配置'; + +comment on column wf_node_config.id is '主键'; + +comment on column wf_node_config.form_id is '表单id'; + +comment on column wf_node_config.form_type is '表单类型'; + +comment on column wf_node_config.node_id is '节点id'; + +comment on column wf_node_config.node_name is '节点名称'; + +comment on column wf_node_config.definition_id is '流程定义id'; + +comment on column wf_node_config.apply_user_task is '是否为申请人节点 (0是 1否)'; + +comment on column wf_node_config.tenant_id is '租户id'; + +comment on column wf_node_config.create_dept is '创建部门'; + +comment on column wf_node_config.create_by is '创建者'; + +comment on column wf_node_config.create_time is '创建时间'; + +comment on column wf_node_config.update_by is '修改者'; + +comment on column wf_node_config.update_time is '修改时间'; + +INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11638, '请假申请', 5, 1, 'leave', 'workflow/leave/index', 1, 0, 'C', '0', '0', 'demo:leave:list', '#', 103, 1, now(), NULL, NULL, '请假申请菜单'); +INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11639, '请假申请查询', 11638, 1, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:query', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11640, '请假申请新增', 11638, 2, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:add', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11641, '请假申请修改', 11638, 3, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:edit', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11642, '请假申请删除', 11638, 4, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:remove', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11643, '请假申请导出', 11638, 5, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:export', '#', 103, 1, now(), NULL, NULL, ''); + +INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (13, '000000', '业务状态', 'wf_business_status', 103, 1, now(), NULL, NULL, '业务状态列表'); +INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (14, '000000', '表单类型', 'wf_form_type', 103, 1, now(), NULL, NULL, '表单类型列表'); + +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (39, '000000', 1, '已撤销', 'cancel', 'wf_business_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '已撤销'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (40, '000000', 2, '草稿', 'draft', 'wf_business_status', '', 'info', 'N', 103, 1, now(), NULL, NULL, '草稿'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (41, '000000', 3, '待审核', 'waiting', 'wf_business_status', '', 'primary', 'N', 103, 1,now(), NULL, NULL, '待审核'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (42, '000000', 4, '已完成', 'finish', 'wf_business_status', '', 'success', 'N', 103, 1, now(), NULL, NULL, '已完成'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (43, '000000', 5, '已作废', 'invalid', 'wf_business_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '已作废'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (44, '000000', 6, '已退回', 'back', 'wf_business_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '已退回'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (45, '000000', 7, '已终止', 'termination', 'wf_business_status', '', 'danger', 'N', 103, 1,now(), NULL, NULL, '已终止'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (46, '000000', 1, '自定义表单', 'static', 'wf_form_type', '', 'success', 'N', 103, 1, now(), NULL, NULL, '自定义表单'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (47, '000000', 2, '动态表单', 'dynamic', 'wf_form_type', '', 'primary', 'N', 103, 1, now(), NULL, NULL, '动态表单'); + +-- 表单管理 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(11628, '表单管理', '11616', '5', 'formManage', 'workflow/formManage/index', 1, 0, 'C', '0', '0', 'workflow:formManage:list', 'tree-table', 103, 1, now(), null, null, '表单管理菜单'); + +-- 表单管理按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(11644, '表单管理查询', 11628, '1', '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:query', '', 103, 1, now(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(11645, '表单管理新增', 11628, '2', '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:add', '', 103, 1, now(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(11646, '表单管理修改', 11628, '3', '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:edit', '', 103, 1, now(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(11647, '表单管理删除', 11628, '4', '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:remove', '', 103, 1, now(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(11648, '表单管理导出', 11628, '5', '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:export', 'tree-table', 103, 1, now(), null, null, ''); diff --git a/script/sql/postgres/postgres_ry_vue_5.X.sql b/script/sql/postgres/postgres_ry_vue_5.X.sql index a6d6f1a03..58a519391 100644 --- a/script/sql/postgres/postgres_ry_vue_5.X.sql +++ b/script/sql/postgres/postgres_ry_vue_5.X.sql @@ -20,7 +20,7 @@ create table sys_social union_id varchar(255) default null::varchar, scope varchar(255) default null::varchar, token_type varchar(255) default null::varchar, - id_token varchar(255) default null::varchar, + id_token varchar(2000) default null::varchar, mac_algorithm varchar(255) default null::varchar, mac_key varchar(255) default null::varchar, code varchar(255) default null::varchar, @@ -69,7 +69,6 @@ comment on column sys_social.del_flag is '删除标志(0代表存在 -- ---------------------------- -- 租户表 -- ---------------------------- -drop table if exists sys_tenant; create table if not exists sys_tenant ( id int8, @@ -128,7 +127,6 @@ insert into sys_tenant values(1, '000000', '管理组', '15888888888', 'XXX有 -- ---------------------------- -- 租户套餐表 -- ---------------------------- -drop table if exists sys_tenant_package; create table if not exists sys_tenant_package ( package_id int8, @@ -164,7 +162,6 @@ comment on column sys_tenant_package.update_time is '更新时间'; -- ---------------------------- -- 1、部门表 -- ---------------------------- -drop table if exists sys_dept; create table if not exists sys_dept ( dept_id int8, @@ -221,7 +218,6 @@ insert into sys_dept values(109, '000000', 102, '0,100,102', '财务部门', -- ---------------------------- -- 2、用户信息表 -- ---------------------------- -drop table if exists sys_user; create table if not exists sys_user ( user_id int8, @@ -276,13 +272,12 @@ comment on column sys_user.remark is '备注'; -- 初始化-用户信息表数据 -- ---------------------------- insert into sys_user values(1, '000000', 103, 'admin', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@163.com', '15888888888', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', now(), 103, 1, now(), null, null, '管理员'); -insert into sys_user values(2, '000000', 105, 'lionli', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@qq.com', '15666666666', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', now(), 103, 1, now(), null, null, '测试员'); - +insert into sys_user VALUES(3, '000000', 108, 'test', '本部门及以下 密码666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', now(), 103, 1, now(), 3, now(), NULL); +insert into sys_user VALUES(4, '000000', 102, 'test1', '仅本人 密码666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', now(), 103, 1, now(), 4, now(), NULL); -- ---------------------------- -- 3、岗位信息表 -- ---------------------------- -drop table if exists sys_post; create table if not exists sys_post ( post_id int8, @@ -325,7 +320,6 @@ insert into sys_post values(4, '000000', 'user', '普通员工', 4, '0', 103, 1 -- ---------------------------- -- 4、角色信息表 -- ---------------------------- -drop table if exists sys_role; create table if not exists sys_role ( role_id int8, @@ -369,13 +363,12 @@ comment on column sys_role.remark is '备注'; -- 初始化-角色信息表数据 -- ---------------------------- insert into sys_role values('1', '000000', '超级管理员', 'superadmin', 1, '1', 't', 't', '0', '0', 103, 1, now(), null, null, '超级管理员'); -insert into sys_role values('2', '000000', '普通角色', 'common', 2, '2', 't', 't', '0', '0', 103, 1, now(), null, null, '普通角色'); - +insert into sys_role values('3', '000000', '本部门及以下', 'test1', 3, '4', 't', 't', '0', '0', 103, 1, now(), NULL, NULL, ''); +insert into sys_role values('4', '000000', '仅本人', 'test2', 4, '5', 't', 't', '0', '0', 103, 1, now(), NULL, NULL, ''); -- ---------------------------- -- 5、菜单权限表 -- ---------------------------- -drop table if exists sys_menu; create table if not exists sys_menu ( menu_id int8, @@ -432,6 +425,7 @@ insert into sys_menu values('6', '系统管理', '0', '2', 'tenant', n insert into sys_menu values('2', '系统监控', '0', '3', 'monitor', null, '', '1', '0', 'M', '0', '0', '', 'monitor', 103, 1, now(), null, null, '系统监控目录'); insert into sys_menu values('3', '系统工具', '0', '4', 'tool', null, '', '1', '0', 'M', '0', '0', '', 'tool', 103, 1, now(), null, null, '系统工具目录'); insert into sys_menu values('4', 'PLUS官网', '0', '5', 'https://gitee.com/dromara/RuoYi-Vue-Plus', null, '', '0', '0', 'M', '0', '0', '', 'guide', 103, 1, now(), null, null, 'RuoYi-Vue-Plus官网地址'); +insert into sys_menu VALUES('5', '测试菜单', '0', '5', 'demo', null, '1', '0', 'M', '0', '0', null, 'star', 103, 1, now(), null, null, '测试菜单'); -- 二级菜单 insert into sys_menu values('100', '用户管理', '1', '1', 'user', 'system/user/index', '', '1', '0', 'C', '0', '0', 'system:user:list', 'user', 103, 1, now(), null, null, '用户管理菜单'); insert into sys_menu values('101', '角色管理', '1', '2', 'role', 'system/role/index', '', '1', '0', 'C', '0', '0', 'system:role:list', 'peoples', 103, 1, now(), null, null, '角色管理菜单'); @@ -456,6 +450,8 @@ insert into sys_menu values('117', 'Admin监控', '2', '5', 'Admin', insert into sys_menu values('118', '文件管理', '1', '10', 'oss', 'system/oss/index', '', '1', '0', 'C', '0', '0', 'system:oss:list', 'upload', 103, 1, now(), null, null, '文件管理菜单'); -- powerjob server控制台 insert into sys_menu values('120', '任务调度中心', '2', '5', 'powerjob', 'monitor/powerjob/index', '', '1', '0', 'C', '0', '0', 'monitor:powerjob:list', 'job', 103, 1, now(), null, null, 'PowerJob控制台菜单'); +-- retry server控制台 +insert into sys_menu values('130', 'EasyRetry控制台', '2', '6', 'easyretry', 'monitor/easyretry/index', '', '1', '0', 'C', '0', '0', 'monitor:easyretry:list', 'job', 103, 1, now(), null, null, 'EasyRetry控制台菜单'); -- 三级菜单 insert into sys_menu values('500', '操作日志', '108', '1', 'operlog', 'monitor/operlog/index', '', '1', '0', 'C', '0', '0', 'monitor:operlog:list', 'form', 103, 1, now(), null, null, '操作日志菜单'); @@ -554,11 +550,24 @@ insert into sys_menu values('1062', '客户端管理新增', '123', '2', '#', ' insert into sys_menu values('1063', '客户端管理修改', '123', '3', '#', '', '', '1', '0', 'F', '0', '0', 'system:client:edit', '#', 103, 1, now(), null, null, ''); insert into sys_menu values('1064', '客户端管理删除', '123', '4', '#', '', '', '1', '0', 'F', '0', '0', 'system:client:remove', '#', 103, 1, now(), null, null, ''); insert into sys_menu values('1065', '客户端管理导出', '123', '5', '#', '', '', '1', '0', 'F', '0', '0', 'system:client:export', '#', 103, 1, now(), null, null, ''); +-- 测试菜单 +INSERT INTO sys_menu VALUES('1500', '测试单表', '5', '1', 'demo', 'demo/demo/index', '', '1', '0', 'C', '0', '0', 'demo:demo:list', '#', 103, 1, now(), NULL, NULL, '测试单表菜单'); +INSERT INTO sys_menu VALUES('1501', '测试单表查询', '1500', '1', '#', '', '', '1', '0', 'F', '0', '0', 'demo:demo:query', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES('1502', '测试单表新增', '1500', '2,' '#', '', '', '1', '0', 'F', '0', '0', 'demo:demo:add', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES('1503', '测试单表修改', '1500', '3', '#', '', '', '1', '0,' 'F', '0', '0', 'demo:demo:edit', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES('1504', '测试单表删除', '1500', '4', '#', '', '', '1', '0', 'F', '0', '0', 'demo:demo:remove', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES('1505', '测试单表导出', '1500', '5', '#', '', '', '1', '0', 'F', '0', '0', 'demo:demo:export', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES('1506', '测试树表', '5', '1', 'tree', 'demo/tree/index', '', '1', '0', 'C', '0', '0', 'demo:tree:list', '#', 103, 1, now(), NULL, NULL, '测试树表菜单'); +INSERT INTO sys_menu VALUES('1507', '测试树表查询', '1506', '1', '#', '', '', '1', '0', 'F', '0', '0', 'demo:tree:query', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES('1508', '测试树表新增', '1506', '2', '#', '', '', '1', '0', 'F', '0', '0', 'demo:tree:add', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES('1509', '测试树表修改', '1506', '3', '#', '', '', '1', '0', 'F', '0', '0', 'demo:tree:edit', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES('1510', '测试树表删除', '1506', '4', '#', '', '', '1', '0', 'F', '0', '0', 'demo:tree:remove', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES('1511', '测试树表导出', '1506', '5', '#', '', '', '1', '0', 'F', '0', '0', 'demo:tree:export', '#', 103, 1, now(), NULL, NULL, ''); + -- ---------------------------- -- 6、用户和角色关联表 用户N-1角色 -- ---------------------------- -drop table if exists sys_user_role; create table if not exists sys_user_role ( user_id int8 not null, @@ -574,13 +583,12 @@ comment on column sys_user_role.role_id is '角色ID'; -- 初始化-用户和角色关联表数据 -- ---------------------------- insert into sys_user_role values ('1', '1'); -insert into sys_user_role values ('2', '2'); - +insert into sys_user_role values ('3', '3'); +insert into sys_user_role values ('4', '4'); -- ---------------------------- -- 7、角色和菜单关联表 角色1-N菜单 -- ---------------------------- -drop table if exists sys_role_menu; create table if not exists sys_role_menu ( role_id int8 not null, @@ -595,95 +603,93 @@ comment on column sys_role_menu.menu_id is '菜单ID'; -- ---------------------------- -- 初始化-角色和菜单关联表数据 -- ---------------------------- -insert into sys_role_menu values ('2', '1'); -insert into sys_role_menu values ('2', '2'); -insert into sys_role_menu values ('2', '3'); -insert into sys_role_menu values ('2', '4'); -insert into sys_role_menu values ('2', '100'); -insert into sys_role_menu values ('2', '101'); -insert into sys_role_menu values ('2', '102'); -insert into sys_role_menu values ('2', '103'); -insert into sys_role_menu values ('2', '104'); -insert into sys_role_menu values ('2', '105'); -insert into sys_role_menu values ('2', '106'); -insert into sys_role_menu values ('2', '107'); -insert into sys_role_menu values ('2', '108'); -insert into sys_role_menu values ('2', '109'); -insert into sys_role_menu values ('2', '110'); -insert into sys_role_menu values ('2', '111'); -insert into sys_role_menu values ('2', '112'); -insert into sys_role_menu values ('2', '113'); -insert into sys_role_menu values ('2', '114'); -insert into sys_role_menu values ('2', '115'); -insert into sys_role_menu values ('2', '116'); -insert into sys_role_menu values ('2', '500'); -insert into sys_role_menu values ('2', '501'); -insert into sys_role_menu values ('2', '1000'); -insert into sys_role_menu values ('2', '1001'); -insert into sys_role_menu values ('2', '1002'); -insert into sys_role_menu values ('2', '1003'); -insert into sys_role_menu values ('2', '1004'); -insert into sys_role_menu values ('2', '1005'); -insert into sys_role_menu values ('2', '1006'); -insert into sys_role_menu values ('2', '1007'); -insert into sys_role_menu values ('2', '1008'); -insert into sys_role_menu values ('2', '1009'); -insert into sys_role_menu values ('2', '1010'); -insert into sys_role_menu values ('2', '1011'); -insert into sys_role_menu values ('2', '1012'); -insert into sys_role_menu values ('2', '1013'); -insert into sys_role_menu values ('2', '1014'); -insert into sys_role_menu values ('2', '1015'); -insert into sys_role_menu values ('2', '1016'); -insert into sys_role_menu values ('2', '1017'); -insert into sys_role_menu values ('2', '1018'); -insert into sys_role_menu values ('2', '1019'); -insert into sys_role_menu values ('2', '1020'); -insert into sys_role_menu values ('2', '1021'); -insert into sys_role_menu values ('2', '1022'); -insert into sys_role_menu values ('2', '1023'); -insert into sys_role_menu values ('2', '1024'); -insert into sys_role_menu values ('2', '1025'); -insert into sys_role_menu values ('2', '1026'); -insert into sys_role_menu values ('2', '1027'); -insert into sys_role_menu values ('2', '1028'); -insert into sys_role_menu values ('2', '1029'); -insert into sys_role_menu values ('2', '1030'); -insert into sys_role_menu values ('2', '1031'); -insert into sys_role_menu values ('2', '1032'); -insert into sys_role_menu values ('2', '1033'); -insert into sys_role_menu values ('2', '1034'); -insert into sys_role_menu values ('2', '1035'); -insert into sys_role_menu values ('2', '1036'); -insert into sys_role_menu values ('2', '1037'); -insert into sys_role_menu values ('2', '1038'); -insert into sys_role_menu values ('2', '1039'); -insert into sys_role_menu values ('2', '1040'); -insert into sys_role_menu values ('2', '1041'); -insert into sys_role_menu values ('2', '1042'); -insert into sys_role_menu values ('2', '1043'); -insert into sys_role_menu values ('2', '1044'); -insert into sys_role_menu values ('2', '1045'); -insert into sys_role_menu values ('2', '1050'); -insert into sys_role_menu values ('2', '1046'); -insert into sys_role_menu values ('2', '1047'); -insert into sys_role_menu values ('2', '1048'); -insert into sys_role_menu values ('2', '1055'); -insert into sys_role_menu values ('2', '1056'); -insert into sys_role_menu values ('2', '1057'); -insert into sys_role_menu values ('2', '1058'); -insert into sys_role_menu values ('2', '1059'); -insert into sys_role_menu values ('2', '1060'); -insert into sys_role_menu values ('2', '1061'); -insert into sys_role_menu values ('2', '1062'); -insert into sys_role_menu values ('2', '1063'); -insert into sys_role_menu values ('2', '1064'); -insert into sys_role_menu values ('2', '1065'); +insert into sys_role_menu values ('3', '1'); +insert into sys_role_menu values ('3', '5'); +insert into sys_role_menu values ('3', '100'); +insert into sys_role_menu values ('3', '101'); +insert into sys_role_menu values ('3', '102'); +insert into sys_role_menu values ('3', '103'); +insert into sys_role_menu values ('3', '104'); +insert into sys_role_menu values ('3', '105'); +insert into sys_role_menu values ('3', '106'); +insert into sys_role_menu values ('3', '107'); +insert into sys_role_menu values ('3', '108'); +insert into sys_role_menu values ('3', '500'); +insert into sys_role_menu values ('3', '501'); +insert into sys_role_menu values ('3', '1001'); +insert into sys_role_menu values ('3', '1002'); +insert into sys_role_menu values ('3', '1003'); +insert into sys_role_menu values ('3', '1004'); +insert into sys_role_menu values ('3', '1005'); +insert into sys_role_menu values ('3', '1006'); +insert into sys_role_menu values ('3', '1007'); +insert into sys_role_menu values ('3', '1008'); +insert into sys_role_menu values ('3', '1009'); +insert into sys_role_menu values ('3', '1010'); +insert into sys_role_menu values ('3', '1011'); +insert into sys_role_menu values ('3', '1012'); +insert into sys_role_menu values ('3', '1013'); +insert into sys_role_menu values ('3', '1014'); +insert into sys_role_menu values ('3', '1015'); +insert into sys_role_menu values ('3', '1016'); +insert into sys_role_menu values ('3', '1017'); +insert into sys_role_menu values ('3', '1018'); +insert into sys_role_menu values ('3', '1019'); +insert into sys_role_menu values ('3', '1020'); +insert into sys_role_menu values ('3', '1021'); +insert into sys_role_menu values ('3', '1022'); +insert into sys_role_menu values ('3', '1023'); +insert into sys_role_menu values ('3', '1024'); +insert into sys_role_menu values ('3', '1025'); +insert into sys_role_menu values ('3', '1026'); +insert into sys_role_menu values ('3', '1027'); +insert into sys_role_menu values ('3', '1028'); +insert into sys_role_menu values ('3', '1029'); +insert into sys_role_menu values ('3', '1030'); +insert into sys_role_menu values ('3', '1031'); +insert into sys_role_menu values ('3', '1032'); +insert into sys_role_menu values ('3', '1033'); +insert into sys_role_menu values ('3', '1034'); +insert into sys_role_menu values ('3', '1035'); +insert into sys_role_menu values ('3', '1036'); +insert into sys_role_menu values ('3', '1037'); +insert into sys_role_menu values ('3', '1038'); +insert into sys_role_menu values ('3', '1039'); +insert into sys_role_menu values ('3', '1040'); +insert into sys_role_menu values ('3', '1041'); +insert into sys_role_menu values ('3', '1042'); +insert into sys_role_menu values ('3', '1043'); +insert into sys_role_menu values ('3', '1044'); +insert into sys_role_menu values ('3', '1045'); +insert into sys_role_menu values ('3', '1500'); +insert into sys_role_menu values ('3', '1501'); +insert into sys_role_menu values ('3', '1502'); +insert into sys_role_menu values ('3', '1503'); +insert into sys_role_menu values ('3', '1504'); +insert into sys_role_menu values ('3', '1505'); +insert into sys_role_menu values ('3', '1506'); +insert into sys_role_menu values ('3', '1507'); +insert into sys_role_menu values ('3', '1508'); +insert into sys_role_menu values ('3', '1509'); +insert into sys_role_menu values ('3', '1510'); +insert into sys_role_menu values ('3', '1511'); +insert into sys_role_menu values ('4', '5'); +insert into sys_role_menu values ('4', '1500'); +insert into sys_role_menu values ('4', '1501'); +insert into sys_role_menu values ('4', '1502'); +insert into sys_role_menu values ('4', '1503'); +insert into sys_role_menu values ('4', '1504'); +insert into sys_role_menu values ('4', '1505'); +insert into sys_role_menu values ('4', '1506'); +insert into sys_role_menu values ('4', '1507'); +insert into sys_role_menu values ('4', '1508'); +insert into sys_role_menu values ('4', '1509'); +insert into sys_role_menu values ('4', '1510'); +insert into sys_role_menu values ('4', '1511'); -- ---------------------------- -- 8、角色和部门关联表 角色1-N部门 -- ---------------------------- -drop table if exists sys_role_dept; create table if not exists sys_role_dept ( role_id int8 not null, @@ -695,18 +701,10 @@ comment on table sys_role_dept is '角色和部门关联表'; comment on column sys_role_dept.role_id is '角色ID'; comment on column sys_role_dept.dept_id is '部门ID'; --- ---------------------------- --- 初始化-角色和部门关联表数据 --- ---------------------------- -insert into sys_role_dept values ('2', '100'); -insert into sys_role_dept values ('2', '101'); -insert into sys_role_dept values ('2', '105'); - -- ---------------------------- -- 9、用户与岗位关联表 用户1-N岗位 -- ---------------------------- -drop table if exists sys_user_post; create table if not exists sys_user_post ( user_id int8 not null, @@ -722,13 +720,10 @@ comment on column sys_user_post.post_id is '岗位ID'; -- 初始化-用户与岗位关联表数据 -- ---------------------------- insert into sys_user_post values ('1', '1'); -insert into sys_user_post values ('2', '2'); - -- ---------------------------- -- 10、操作日志记录 -- ---------------------------- -drop table if exists sys_oper_log; create table if not exists sys_oper_log ( oper_id int8, @@ -779,7 +774,6 @@ comment on column sys_oper_log.cost_time is '消耗时间'; -- ---------------------------- -- 11、字典类型表 -- ---------------------------- -drop table if exists sys_dict_type; create table if not exists sys_dict_type ( dict_id int8, @@ -823,7 +817,6 @@ insert into sys_dict_type values(12, '000000', '设备类型', 'sys_device_type' -- ---------------------------- -- 12、字典数据表 -- ---------------------------- -drop table if exists sys_dict_data; create table if not exists sys_dict_data ( dict_code int8, @@ -900,7 +893,6 @@ insert into sys_dict_data values(38, '000000', 0, '小程序', 'xcx', ' -- ---------------------------- -- 13、参数配置表 -- ---------------------------- -drop table if exists sys_config; create table if not exists sys_config ( config_id int8, @@ -942,7 +934,6 @@ insert into sys_config values(11, '000000', 'OSS预览列表资源开关', -- ---------------------------- -- 14、系统访问记录 -- ---------------------------- -drop table if exists sys_logininfor; create table if not exists sys_logininfor ( info_id int8, @@ -980,7 +971,6 @@ comment on column sys_logininfor.login_time is '访问时间'; -- ---------------------------- -- 17、通知公告表 -- ---------------------------- -drop table if exists sys_notice; create table if not exists sys_notice ( notice_id int8, @@ -1022,7 +1012,6 @@ insert into sys_notice values('2', '000000', '维护通知:2018-07-01 系统 -- ---------------------------- -- 18、代码生成业务表 -- ---------------------------- -drop table if exists gen_table; create table if not exists gen_table ( table_id int8, @@ -1077,7 +1066,6 @@ comment on column gen_table.remark is '备注'; -- ---------------------------- -- 19、代码生成业务表字段 -- ---------------------------- -drop table if exists gen_table_column; create table if not exists gen_table_column ( column_id int8, @@ -1134,7 +1122,6 @@ comment on column gen_table_column.update_time is '更新时间'; -- ---------------------------- -- OSS对象存储表 -- ---------------------------- -drop table if exists sys_oss; create table if not exists sys_oss ( oss_id int8, @@ -1169,7 +1156,6 @@ comment on column sys_oss.service is '服务商'; -- ---------------------------- -- OSS对象存储动态配置表 -- ---------------------------- -drop table if exists sys_oss_config; create table if not exists sys_oss_config ( oss_config_id int8, @@ -1226,7 +1212,6 @@ insert into sys_oss_config values (5, '000000', 'image', 'ruoyi', 'r -- ---------------------------- -- 系统授权表 -- ---------------------------- -drop table if exists sys_client; create table sys_client ( id int8, client_id varchar(64) default ''::varchar, @@ -1266,6 +1251,100 @@ comment on column sys_client.update_time is '更新时间'; insert into sys_client values (1, 'e5cd7e4891bf95d1d19206ce24a7b32e', 'pc', 'pc123', 'password,social', 'pc', 1800, 604800, 0, 0, 103, 1, now(), 1, now()); insert into sys_client values (2, '428a8310cd442757ae699df5d894f051', 'app', 'app123', 'password,sms,social', 'android', 1800, 604800, 0, 0, 103, 1, now(), 1, now()); +create table if not exists test_demo +( + id int8, + tenant_id varchar(20) default '000000', + dept_id int8, + user_id int8, + order_num int4 default 0, + test_key varchar(255), + value varchar(255), + version int4 default 0, + create_time timestamp, + create_dept int8, + create_by int8, + update_time timestamp, + update_by int8, + del_flag int4 default 0 +); + +comment on table test_demo is '测试单表'; +comment on column test_demo.id is '主键'; +comment on column test_demo.tenant_id is '租户编号'; +comment on column test_demo.dept_id is '部门id'; +comment on column test_demo.user_id is '用户id'; +comment on column test_demo.order_num is '排序号'; +comment on column test_demo.test_key is 'key键'; +comment on column test_demo.value is '值'; +comment on column test_demo.version is '版本'; +comment on column test_demo.create_dept is '创建部门'; +comment on column test_demo.create_time is '创建时间'; +comment on column test_demo.create_by is '创建人'; +comment on column test_demo.update_time is '更新时间'; +comment on column test_demo.update_by is '更新人'; +comment on column test_demo.del_flag is '删除标志'; + +create table if not exists test_tree +( + id int8, + tenant_id varchar(20) default '000000', + parent_id int8 default 0, + dept_id int8, + user_id int8, + tree_name varchar(255), + version int4 default 0, + create_time timestamp, + create_dept int8, + create_by int8, + update_time timestamp, + update_by int8, + del_flag integer default 0 +); + +comment on table test_tree is '测试树表'; +comment on column test_tree.id is '主键'; +comment on column test_tree.tenant_id is '租户编号'; +comment on column test_tree.parent_id is '父id'; +comment on column test_tree.dept_id is '部门id'; +comment on column test_tree.user_id is '用户id'; +comment on column test_tree.tree_name is '值'; +comment on column test_tree.version is '版本'; +comment on column test_tree.create_dept is '创建部门'; +comment on column test_tree.create_time is '创建时间'; +comment on column test_tree.create_by is '创建人'; +comment on column test_tree.update_time is '更新时间'; +comment on column test_tree.update_by is '更新人'; +comment on column test_tree.del_flag is '删除标志'; + +INSERT INTO test_demo VALUES (1, '000000', 102, 4, 1, '测试数据权限', '测试', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (2, '000000', 102, 3, 2, '子节点1', '111', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (3, '000000', 102, 3, 3, '子节点2', '222', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (4, '000000', 108, 4, 4, '测试数据', 'demo', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (5, '000000', 108, 3, 13, '子节点11', '1111', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (6, '000000', 108, 3, 12, '子节点22', '2222', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (7, '000000', 108, 3, 11, '子节点33', '3333', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (8, '000000', 108, 3, 10, '子节点44', '4444', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (9, '000000', 108, 3, 9, '子节点55', '5555', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (10, '000000', 108, 3, 8, '子节点66', '6666', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (11, '000000', 108, 3, 7, '子节点77', '7777', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (12, '000000', 108, 3, 6, '子节点88', '8888', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (13, '000000', 108, 3, 5, '子节点99', '9999', 0, 103, now(), 1, NULL, NULL, 0); + +INSERT INTO test_tree VALUES (1, '000000', 0, 102, 4, '测试数据权限', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (2, '000000', 1, 102, 3, '子节点1', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (3, '000000', 2, 102, 3, '子节点2', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (4, '000000', 0, 108, 4, '测试树1', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (5, '000000', 4, 108, 3, '子节点11', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (6, '000000', 4, 108, 3, '子节点22', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (7, '000000', 4, 108, 3, '子节点33', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (8, '000000', 5, 108, 3, '子节点44', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (9, '000000', 6, 108, 3, '子节点55', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (10, '000000', 7, 108, 3, '子节点66', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (11, '000000', 7, 108, 3, '子节点77', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (12, '000000', 10, 108, 3, '子节点88', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (13, '000000', 10, 108, 3, '子节点99', 0, 103, now(), 1, NULL, NULL, 0); + -- 字符串自动转时间 避免框架时间查询报错问题 create or replace function cast_varchar_to_timestamp(varchar) returns timestamptz as $$ select to_timestamp($1, 'yyyy-mm-dd hh24:mi:ss'); diff --git a/script/sql/postgres/postgres_test.sql b/script/sql/postgres/postgres_test.sql deleted file mode 100644 index 179096b3d..000000000 --- a/script/sql/postgres/postgres_test.sql +++ /dev/null @@ -1,204 +0,0 @@ -DROP TABLE if EXISTS test_demo; -create table if not exists test_demo -( - id int8, - tenant_id varchar(20) default '000000', - dept_id int8, - user_id int8, - order_num int4 default 0, - test_key varchar(255), - value varchar(255), - version int4 default 0, - create_time timestamp, - create_dept int8, - create_by int8, - update_time timestamp, - update_by int8, - del_flag int4 default 0 -); - -comment on table test_demo is '测试单表'; -comment on column test_demo.id is '主键'; -comment on column test_demo.tenant_id is '租户编号'; -comment on column test_demo.dept_id is '部门id'; -comment on column test_demo.user_id is '用户id'; -comment on column test_demo.order_num is '排序号'; -comment on column test_demo.test_key is 'key键'; -comment on column test_demo.value is '值'; -comment on column test_demo.version is '版本'; -comment on column test_demo.create_dept is '创建部门'; -comment on column test_demo.create_time is '创建时间'; -comment on column test_demo.create_by is '创建人'; -comment on column test_demo.update_time is '更新时间'; -comment on column test_demo.update_by is '更新人'; -comment on column test_demo.del_flag is '删除标志'; - -DROP TABLE if EXISTS test_tree; -create table if not exists test_tree -( - id int8, - tenant_id varchar(20) default '000000', - parent_id int8 default 0, - dept_id int8, - user_id int8, - tree_name varchar(255), - version int4 default 0, - create_time timestamp, - create_dept int8, - create_by int8, - update_time timestamp, - update_by int8, - del_flag integer default 0 -); - -comment on table test_tree is '测试树表'; -comment on column test_tree.id is '主键'; -comment on column test_tree.tenant_id is '租户编号'; -comment on column test_tree.parent_id is '父id'; -comment on column test_tree.dept_id is '部门id'; -comment on column test_tree.user_id is '用户id'; -comment on column test_tree.tree_name is '值'; -comment on column test_tree.version is '版本'; -comment on column test_tree.create_dept is '创建部门'; -comment on column test_tree.create_time is '创建时间'; -comment on column test_tree.create_by is '创建人'; -comment on column test_tree.update_time is '更新时间'; -comment on column test_tree.update_by is '更新人'; -comment on column test_tree.del_flag is '删除标志'; - -INSERT INTO sys_user(user_id, tenant_id, dept_id, user_name, nick_name, user_type, email, phonenumber, sex, avatar, password, status, del_flag, login_ip, login_date, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (3, '000000', 108, 'test', '本部门及以下 密码666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', now(), 103, 1, now(), 3, now(), NULL); -INSERT INTO sys_user(user_id, tenant_id, dept_id, user_name, nick_name, user_type, email, phonenumber, sex, avatar, password, status, del_flag, login_ip, login_date, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (4, '000000', 102, 'test1', '仅本人 密码666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', now(), 103, 1, now(), 4, now(), NULL); - -INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (5, '测试菜单', 0, 5, 'demo', NULL, 1, 0, 'M', '0', '0', NULL, 'star', 103, 1, now(), NULL, NULL, ''); - -INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (1500, '测试单表', 5, 1, 'demo', 'demo/demo/index', 1, 0, 'C', '0', '0', 'demo:demo:list', '#', 103, 1, now(), NULL, NULL, '测试单表菜单'); -INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (1501, '测试单表查询', 1500, 1, '#', '', 1, 0, 'F', '0', '0', 'demo:demo:query', '#', 103, 1, now(), NULL, NULL, ''); -INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (1502, '测试单表新增', 1500, 2, '#', '', 1, 0, 'F', '0', '0', 'demo:demo:add', '#', 103, 1, now(), NULL, NULL, ''); -INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (1503, '测试单表修改', 1500, 3, '#', '', 1, 0, 'F', '0', '0', 'demo:demo:edit', '#', 103, 1, now(), NULL, NULL, ''); -INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (1504, '测试单表删除', 1500, 4, '#', '', 1, 0, 'F', '0', '0', 'demo:demo:remove', '#', 103, 1, now(), NULL, NULL, ''); -INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (1505, '测试单表导出', 1500, 5, '#', '', 1, 0, 'F', '0', '0', 'demo:demo:export', '#', 103, 1, now(), NULL, NULL, ''); - -INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (1506, '测试树表', 5, 1, 'tree', 'demo/tree/index', 1, 0, 'C', '0', '0', 'demo:tree:list', '#', 103, 1, now(), NULL, NULL, '测试树表菜单'); -INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (1507, '测试树表查询', 1506, 1, '#', '', 1, 0, 'F', '0', '0', 'demo:tree:query', '#', 103, 1, now(), NULL, NULL, ''); -INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (1508, '测试树表新增', 1506, 2, '#', '', 1, 0, 'F', '0', '0', 'demo:tree:add', '#', 103, 1, now(), NULL, NULL, ''); -INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (1509, '测试树表修改', 1506, 3, '#', '', 1, 0, 'F', '0', '0', 'demo:tree:edit', '#', 103, 1, now(), NULL, NULL, ''); -INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (1510, '测试树表删除', 1506, 4, '#', '', 1, 0, 'F', '0', '0', 'demo:tree:remove', '#', 103, 1, now(), NULL, NULL, ''); -INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (1511, '测试树表导出', 1506, 5, '#', '', 1, 0, 'F', '0', '0', 'demo:tree:export', '#', 103, 1, now(), NULL, NULL, ''); - -INSERT INTO sys_role(role_id, tenant_id, role_name, role_key, role_sort, data_scope, menu_check_strictly, dept_check_strictly, status, del_flag, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (3, '000000', '本部门及以下', 'test1', 3, '4', 't', 't', '0', '0', 103, 1, now(), 1, NULL, NULL); -INSERT INTO sys_role(role_id, tenant_id, role_name, role_key, role_sort, data_scope, menu_check_strictly, dept_check_strictly, status, del_flag, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (4, '000000', '仅本人', 'test2', 4, '5', 't', 't', '0', '0', 103, 1, now(), 1, NULL, NULL); - -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 5); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 100); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 101); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 102); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 103); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 104); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 105); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 106); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 107); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 108); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 500); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 501); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1001); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1002); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1003); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1004); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1005); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1006); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1007); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1008); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1009); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1010); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1011); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1012); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1013); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1014); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1015); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1016); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1017); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1018); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1019); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1020); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1021); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1022); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1023); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1024); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1025); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1026); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1027); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1028); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1029); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1030); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1031); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1032); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1033); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1034); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1035); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1036); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1037); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1038); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1039); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1040); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1041); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1042); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1043); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1044); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1045); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1500); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1501); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1502); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1503); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1504); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1505); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1506); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1507); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1508); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1509); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1510); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1511); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (4, 5); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (4, 1500); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (4, 1501); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (4, 1502); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (4, 1503); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (4, 1504); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (4, 1505); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (4, 1506); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (4, 1507); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (4, 1508); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (4, 1509); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (4, 1510); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (4, 1511); - -INSERT INTO sys_user_role(user_id, role_id) VALUES (3, 3); -INSERT INTO sys_user_role(user_id, role_id) VALUES (4, 4); - -INSERT INTO test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (1, '000000', 102, 4, 1, '测试数据权限', '测试', 0, 103, now(), 1, NULL, NULL, 0); -INSERT INTO test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (2, '000000', 102, 3, 2, '子节点1', '111', 0, 103, now(), 1, NULL, NULL, 0); -INSERT INTO test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (3, '000000', 102, 3, 3, '子节点2', '222', 0, 103, now(), 1, NULL, NULL, 0); -INSERT INTO test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (4, '000000', 108, 4, 4, '测试数据', 'demo', 0, 103, now(), 1, NULL, NULL, 0); -INSERT INTO test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (5, '000000', 108, 3, 13, '子节点11', '1111', 0, 103, now(), 1, NULL, NULL, 0); -INSERT INTO test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (6, '000000', 108, 3, 12, '子节点22', '2222', 0, 103, now(), 1, NULL, NULL, 0); -INSERT INTO test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (7, '000000', 108, 3, 11, '子节点33', '3333', 0, 103, now(), 1, NULL, NULL, 0); -INSERT INTO test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (8, '000000', 108, 3, 10, '子节点44', '4444', 0, 103, now(), 1, NULL, NULL, 0); -INSERT INTO test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (9, '000000', 108, 3, 9, '子节点55', '5555', 0, 103, now(), 1, NULL, NULL, 0); -INSERT INTO test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (10, '000000', 108, 3, 8, '子节点66', '6666', 0, 103, now(), 1, NULL, NULL, 0); -INSERT INTO test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (11, '000000', 108, 3, 7, '子节点77', '7777', 0, 103, now(), 1, NULL, NULL, 0); -INSERT INTO test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (12, '000000', 108, 3, 6, '子节点88', '8888', 0, 103, now(), 1, NULL, NULL, 0); -INSERT INTO test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (13, '000000', 108, 3, 5, '子节点99', '9999', 0, 103, now(), 1, NULL, NULL, 0); - -INSERT INTO test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (1, '000000', 0, 102, 4, '测试数据权限', 0, 103, now(), 1, NULL, NULL, 0); -INSERT INTO test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (2, '000000', 1, 102, 3, '子节点1', 0, 103, now(), 1, NULL, NULL, 0); -INSERT INTO test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (3, '000000', 2, 102, 3, '子节点2', 0, 103, now(), 1, NULL, NULL, 0); -INSERT INTO test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (4, '000000', 0, 108, 4, '测试树1', 0, 103, now(), 1, NULL, NULL, 0); -INSERT INTO test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (5, '000000', 4, 108, 3, '子节点11', 0, 103, now(), 1, NULL, NULL, 0); -INSERT INTO test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (6, '000000', 4, 108, 3, '子节点22', 0, 103, now(), 1, NULL, NULL, 0); -INSERT INTO test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (7, '000000', 4, 108, 3, '子节点33', 0, 103, now(), 1, NULL, NULL, 0); -INSERT INTO test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (8, '000000', 5, 108, 3, '子节点44', 0, 103, now(), 1, NULL, NULL, 0); -INSERT INTO test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (9, '000000', 6, 108, 3, '子节点55', 0, 103, now(), 1, NULL, NULL, 0); -INSERT INTO test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (10, '000000', 7, 108, 3, '子节点66', 0, 103, now(), 1, NULL, NULL, 0); -INSERT INTO test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (11, '000000', 7, 108, 3, '子节点77', 0, 103, now(), 1, NULL, NULL, 0); -INSERT INTO test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (12, '000000', 10, 108, 3, '子节点88', 0, 103, now(), 1, NULL, NULL, 0); -INSERT INTO test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (13, '000000', 10, 108, 3, '子节点99', 0, 103, now(), 1, NULL, NULL, 0); diff --git a/script/sql/ry_vue_5.X.sql b/script/sql/ry_vue_5.X.sql index ea365bd01..8e8822c80 100644 --- a/script/sql/ry_vue_5.X.sql +++ b/script/sql/ry_vue_5.X.sql @@ -1,7 +1,6 @@ -- ---------------------------- -- 第三方平台授权表 -- ---------------------------- -drop table if exists sys_social; create table sys_social ( id bigint not null comment '主键', @@ -21,7 +20,7 @@ create table sys_social union_id varchar(255) default null comment '用户的 unionid', scope varchar(255) default null comment '授予的权限,部分平台可能没有', token_type varchar(255) default null comment '个别平台的授权信息,部分平台可能没有', - id_token varchar(255) default null comment 'id token,部分平台可能没有', + id_token varchar(2000) default null comment 'id token,部分平台可能没有', mac_algorithm varchar(255) default null comment '小米平台用户的附带属性,部分平台可能没有', mac_key varchar(255) default null comment '小米平台用户的附带属性,部分平台可能没有', code varchar(255) default null comment '用户的授权code,部分平台可能没有', @@ -40,7 +39,6 @@ create table sys_social -- ---------------------------- -- 租户表 -- ---------------------------- -drop table if exists sys_tenant; create table sys_tenant ( id bigint(20) not null comment 'id', @@ -77,7 +75,6 @@ insert into sys_tenant values(1, '000000', '管理组', '15888888888', 'XXX有 -- ---------------------------- -- 租户套餐表 -- ---------------------------- -drop table if exists sys_tenant_package; create table sys_tenant_package ( package_id bigint(20) not null comment '租户套餐id', package_name varchar(20) comment '套餐名称', @@ -98,7 +95,6 @@ create table sys_tenant_package ( -- ---------------------------- -- 1、部门表 -- ---------------------------- -drop table if exists sys_dept; create table sys_dept ( dept_id bigint(20) not null comment '部门id', tenant_id varchar(20) default '000000' comment '租户编号', @@ -139,7 +135,6 @@ insert into sys_dept values(109, '000000', 102, '0,100,102', '财务部门', -- ---------------------------- -- 2、用户信息表 -- ---------------------------- -drop table if exists sys_user; create table sys_user ( user_id bigint(20) not null comment '用户ID', tenant_id varchar(20) default '000000' comment '租户编号', @@ -169,13 +164,12 @@ create table sys_user ( -- 初始化-用户信息表数据 -- ---------------------------- insert into sys_user values(1, '000000', 103, 'admin', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@163.com', '15888888888', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 103, 1, sysdate(), null, null, '管理员'); -insert into sys_user values(2, '000000', 105, 'lionli', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@qq.com', '15666666666', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 103, 1, sysdate(), null, null, '测试员'); - +insert into sys_user values(3, '000000', 108, 'test', '本部门及以下 密码666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', sysdate(), 103, 1, sysdate(), 3, sysdate(), null); +insert into sys_user values(4, '000000', 102, 'test1', '仅本人 密码666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', sysdate(), 103, 1, sysdate(), 4, sysdate(), null); -- ---------------------------- -- 3、岗位信息表 -- ---------------------------- -drop table if exists sys_post; create table sys_post ( post_id bigint(20) not null comment '岗位ID', @@ -205,7 +199,6 @@ insert into sys_post values(4, '000000', 'user', '普通员工', 4, '0', 103, 1 -- ---------------------------- -- 4、角色信息表 -- ---------------------------- -drop table if exists sys_role; create table sys_role ( role_id bigint(20) not null comment '角色ID', tenant_id varchar(20) default '000000' comment '租户编号', @@ -230,13 +223,12 @@ create table sys_role ( -- 初始化-角色信息表数据 -- ---------------------------- insert into sys_role values(1, '000000', '超级管理员', 'superadmin', 1, 1, 1, 1, '0', '0', 103, 1, sysdate(), null, null, '超级管理员'); -insert into sys_role values(2, '000000', '普通角色', 'common', 2, 2, 1, 1, '0', '0', 103, 1, sysdate(), null, null, '普通角色'); - +insert into sys_role values(3, '000000', '本部门及以下', 'test1', 3, 4, 1, 1, '0', '0', 103, 1, sysdate(), null, null, ''); +insert into sys_role values(4, '000000', '仅本人', 'test2', 4, 5, 1, 1, '0', '0', 103, 1, sysdate(), null, null, ''); -- ---------------------------- -- 5、菜单权限表 -- ---------------------------- -drop table if exists sys_menu; create table sys_menu ( menu_id bigint(20) not null comment '菜单ID', menu_name varchar(50) not null comment '菜单名称', @@ -270,6 +262,7 @@ insert into sys_menu values('6', '租户管理', '0', '2', 'tenant', n insert into sys_menu values('2', '系统监控', '0', '3', 'monitor', null, '', 1, 0, 'M', '0', '0', '', 'monitor', 103, 1, sysdate(), null, null, '系统监控目录'); insert into sys_menu values('3', '系统工具', '0', '4', 'tool', null, '', 1, 0, 'M', '0', '0', '', 'tool', 103, 1, sysdate(), null, null, '系统工具目录'); insert into sys_menu values('4', 'PLUS官网', '0', '5', 'https://gitee.com/dromara/RuoYi-Vue-Plus', null, '', 0, 0, 'M', '0', '0', '', 'guide', 103, 1, sysdate(), null, null, 'RuoYi-Vue-Plus官网地址'); +insert into sys_menu values('5', '测试菜单', '0', '5', 'demo', null, '', 1, 0, 'M', '0', '0', '', 'star', 103, 1, sysdate(), null, null, '测试菜单'); -- 二级菜单 insert into sys_menu values('100', '用户管理', '1', '1', 'user', 'system/user/index', '', 1, 0, 'C', '0', '0', 'system:user:list', 'user', 103, 1, sysdate(), null, null, '用户管理菜单'); insert into sys_menu values('101', '角色管理', '1', '2', 'role', 'system/role/index', '', 1, 0, 'C', '0', '0', 'system:role:list', 'peoples', 103, 1, sysdate(), null, null, '角色管理菜单'); @@ -293,7 +286,9 @@ insert into sys_menu values('117', 'Admin监控', '2', '5', 'Admin', -- oss菜单 insert into sys_menu values('118', '文件管理', '1', '10', 'oss', 'system/oss/index', '', 1, 0, 'C', '0', '0', 'system:oss:list', 'upload', 103, 1, sysdate(), null, null, '文件管理菜单'); -- powerjob server控制台 -insert into sys_menu values('120', '任务调度中心', '2', '5', 'powerjob', 'monitor/powerjob/index', '', 1, 0, 'C', '0', '0', 'monitor:powerjob:list', 'job', 103, 1, sysdate(), null, null, 'PowerJob控制台菜单'); +insert into sys_menu values('120', '任务调度中心', '2', '5', 'powerjob', 'monitor/powerjob/index', '', 1, 0, 'C', '0', '0', 'monitor:powerjob:list', 'job', 103, 1, sysdate(), null, null, 'PowerJob控制台菜单'); +-- retry server控制台 +insert into sys_menu values('130', 'EasyRetry控制台', '2', '6', 'easyretry', 'monitor/easyretry/index', '', 1, 0, 'C', '0', '0', 'monitor:easyretry:list', 'job', 103, 1, sysdate(), null, null, 'EasyRetry控制台菜单'); -- 三级菜单 insert into sys_menu values('500', '操作日志', '108', '1', 'operlog', 'monitor/operlog/index', '', 1, 0, 'C', '0', '0', 'monitor:operlog:list', 'form', 103, 1, sysdate(), null, null, '操作日志菜单'); @@ -393,11 +388,23 @@ insert into sys_menu values('1062', '客户端管理新增', '123', '2', '#', ' insert into sys_menu values('1063', '客户端管理修改', '123', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:edit', '#', 103, 1, sysdate(), null, null, ''); insert into sys_menu values('1064', '客户端管理删除', '123', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:remove', '#', 103, 1, sysdate(), null, null, ''); insert into sys_menu values('1065', '客户端管理导出', '123', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:export', '#', 103, 1, sysdate(), null, null, ''); +-- 测试菜单 +insert into sys_menu values('1500', '测试单表', '5', '1', 'demo', 'demo/demo/index', '', 1, 0, 'C', '0', '0', 'demo:demo:list', '#', 103, 1, sysdate(), null, null, '测试单表菜单'); +insert into sys_menu values('1501', '测试单表查询', '1500', '1', '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1502', '测试单表新增', '1500', '2', '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1503', '测试单表修改', '1500', '3', '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1504', '测试单表删除', '1500', '4', '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1505', '测试单表导出', '1500', '5', '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:export', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1506', '测试树表', '5', '1', 'tree', 'demo/tree/index', '', 1, 0, 'C', '0', '0', 'demo:tree:list', '#', 103, 1, sysdate(), null, null, '测试树表菜单'); +insert into sys_menu values('1507', '测试树表查询', '1506', '1', '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1508', '测试树表新增', '1506', '2', '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1509', '测试树表修改', '1506', '3', '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1510', '测试树表删除', '1506', '4', '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1511', '测试树表导出', '1506', '5', '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:export', '#', 103, 1, sysdate(), null, null, ''); -- ---------------------------- -- 6、用户和角色关联表 用户N-1角色 -- ---------------------------- -drop table if exists sys_user_role; create table sys_user_role ( user_id bigint(20) not null comment '用户ID', role_id bigint(20) not null comment '角色ID', @@ -408,13 +415,12 @@ create table sys_user_role ( -- 初始化-用户和角色关联表数据 -- ---------------------------- insert into sys_user_role values ('1', '1'); -insert into sys_user_role values ('2', '2'); - +insert into sys_user_role values ('3', '3'); +insert into sys_user_role values ('4', '4'); -- ---------------------------- -- 7、角色和菜单关联表 角色1-N菜单 -- ---------------------------- -drop table if exists sys_role_menu; create table sys_role_menu ( role_id bigint(20) not null comment '角色ID', menu_id bigint(20) not null comment '菜单ID', @@ -424,113 +430,102 @@ create table sys_role_menu ( -- ---------------------------- -- 初始化-角色和菜单关联表数据 -- ---------------------------- -insert into sys_role_menu values ('2', '1'); -insert into sys_role_menu values ('2', '2'); -insert into sys_role_menu values ('2', '3'); -insert into sys_role_menu values ('2', '4'); -insert into sys_role_menu values ('2', '100'); -insert into sys_role_menu values ('2', '101'); -insert into sys_role_menu values ('2', '102'); -insert into sys_role_menu values ('2', '103'); -insert into sys_role_menu values ('2', '104'); -insert into sys_role_menu values ('2', '105'); -insert into sys_role_menu values ('2', '106'); -insert into sys_role_menu values ('2', '107'); -insert into sys_role_menu values ('2', '108'); -insert into sys_role_menu values ('2', '109'); -insert into sys_role_menu values ('2', '110'); -insert into sys_role_menu values ('2', '111'); -insert into sys_role_menu values ('2', '112'); -insert into sys_role_menu values ('2', '113'); -insert into sys_role_menu values ('2', '114'); -insert into sys_role_menu values ('2', '115'); -insert into sys_role_menu values ('2', '116'); -insert into sys_role_menu values ('2', '500'); -insert into sys_role_menu values ('2', '501'); -insert into sys_role_menu values ('2', '1000'); -insert into sys_role_menu values ('2', '1001'); -insert into sys_role_menu values ('2', '1002'); -insert into sys_role_menu values ('2', '1003'); -insert into sys_role_menu values ('2', '1004'); -insert into sys_role_menu values ('2', '1005'); -insert into sys_role_menu values ('2', '1006'); -insert into sys_role_menu values ('2', '1007'); -insert into sys_role_menu values ('2', '1008'); -insert into sys_role_menu values ('2', '1009'); -insert into sys_role_menu values ('2', '1010'); -insert into sys_role_menu values ('2', '1011'); -insert into sys_role_menu values ('2', '1012'); -insert into sys_role_menu values ('2', '1013'); -insert into sys_role_menu values ('2', '1014'); -insert into sys_role_menu values ('2', '1015'); -insert into sys_role_menu values ('2', '1016'); -insert into sys_role_menu values ('2', '1017'); -insert into sys_role_menu values ('2', '1018'); -insert into sys_role_menu values ('2', '1019'); -insert into sys_role_menu values ('2', '1020'); -insert into sys_role_menu values ('2', '1021'); -insert into sys_role_menu values ('2', '1022'); -insert into sys_role_menu values ('2', '1023'); -insert into sys_role_menu values ('2', '1024'); -insert into sys_role_menu values ('2', '1025'); -insert into sys_role_menu values ('2', '1026'); -insert into sys_role_menu values ('2', '1027'); -insert into sys_role_menu values ('2', '1028'); -insert into sys_role_menu values ('2', '1029'); -insert into sys_role_menu values ('2', '1030'); -insert into sys_role_menu values ('2', '1031'); -insert into sys_role_menu values ('2', '1032'); -insert into sys_role_menu values ('2', '1033'); -insert into sys_role_menu values ('2', '1034'); -insert into sys_role_menu values ('2', '1035'); -insert into sys_role_menu values ('2', '1036'); -insert into sys_role_menu values ('2', '1037'); -insert into sys_role_menu values ('2', '1038'); -insert into sys_role_menu values ('2', '1039'); -insert into sys_role_menu values ('2', '1040'); -insert into sys_role_menu values ('2', '1041'); -insert into sys_role_menu values ('2', '1042'); -insert into sys_role_menu values ('2', '1043'); -insert into sys_role_menu values ('2', '1044'); -insert into sys_role_menu values ('2', '1045'); -insert into sys_role_menu values ('2', '1050'); -insert into sys_role_menu values ('2', '1046'); -insert into sys_role_menu values ('2', '1047'); -insert into sys_role_menu values ('2', '1048'); -insert into sys_role_menu values ('2', '1055'); -insert into sys_role_menu values ('2', '1056'); -insert into sys_role_menu values ('2', '1057'); -insert into sys_role_menu values ('2', '1058'); -insert into sys_role_menu values ('2', '1059'); -insert into sys_role_menu values ('2', '1060'); -insert into sys_role_menu values ('2', '1061'); -insert into sys_role_menu values ('2', '1062'); -insert into sys_role_menu values ('2', '1063'); -insert into sys_role_menu values ('2', '1064'); -insert into sys_role_menu values ('2', '1065'); +insert into sys_role_menu values ('3', '1'); +insert into sys_role_menu values ('3', '5'); +insert into sys_role_menu values ('3', '100'); +insert into sys_role_menu values ('3', '101'); +insert into sys_role_menu values ('3', '102'); +insert into sys_role_menu values ('3', '103'); +insert into sys_role_menu values ('3', '104'); +insert into sys_role_menu values ('3', '105'); +insert into sys_role_menu values ('3', '106'); +insert into sys_role_menu values ('3', '107'); +insert into sys_role_menu values ('3', '108'); +insert into sys_role_menu values ('3', '500'); +insert into sys_role_menu values ('3', '501'); +insert into sys_role_menu values ('3', '1001'); +insert into sys_role_menu values ('3', '1002'); +insert into sys_role_menu values ('3', '1003'); +insert into sys_role_menu values ('3', '1004'); +insert into sys_role_menu values ('3', '1005'); +insert into sys_role_menu values ('3', '1006'); +insert into sys_role_menu values ('3', '1007'); +insert into sys_role_menu values ('3', '1008'); +insert into sys_role_menu values ('3', '1009'); +insert into sys_role_menu values ('3', '1010'); +insert into sys_role_menu values ('3', '1011'); +insert into sys_role_menu values ('3', '1012'); +insert into sys_role_menu values ('3', '1013'); +insert into sys_role_menu values ('3', '1014'); +insert into sys_role_menu values ('3', '1015'); +insert into sys_role_menu values ('3', '1016'); +insert into sys_role_menu values ('3', '1017'); +insert into sys_role_menu values ('3', '1018'); +insert into sys_role_menu values ('3', '1019'); +insert into sys_role_menu values ('3', '1020'); +insert into sys_role_menu values ('3', '1021'); +insert into sys_role_menu values ('3', '1022'); +insert into sys_role_menu values ('3', '1023'); +insert into sys_role_menu values ('3', '1024'); +insert into sys_role_menu values ('3', '1025'); +insert into sys_role_menu values ('3', '1026'); +insert into sys_role_menu values ('3', '1027'); +insert into sys_role_menu values ('3', '1028'); +insert into sys_role_menu values ('3', '1029'); +insert into sys_role_menu values ('3', '1030'); +insert into sys_role_menu values ('3', '1031'); +insert into sys_role_menu values ('3', '1032'); +insert into sys_role_menu values ('3', '1033'); +insert into sys_role_menu values ('3', '1034'); +insert into sys_role_menu values ('3', '1035'); +insert into sys_role_menu values ('3', '1036'); +insert into sys_role_menu values ('3', '1037'); +insert into sys_role_menu values ('3', '1038'); +insert into sys_role_menu values ('3', '1039'); +insert into sys_role_menu values ('3', '1040'); +insert into sys_role_menu values ('3', '1041'); +insert into sys_role_menu values ('3', '1042'); +insert into sys_role_menu values ('3', '1043'); +insert into sys_role_menu values ('3', '1044'); +insert into sys_role_menu values ('3', '1045'); +insert into sys_role_menu values ('3', '1500'); +insert into sys_role_menu values ('3', '1501'); +insert into sys_role_menu values ('3', '1502'); +insert into sys_role_menu values ('3', '1503'); +insert into sys_role_menu values ('3', '1504'); +insert into sys_role_menu values ('3', '1505'); +insert into sys_role_menu values ('3', '1506'); +insert into sys_role_menu values ('3', '1507'); +insert into sys_role_menu values ('3', '1508'); +insert into sys_role_menu values ('3', '1509'); +insert into sys_role_menu values ('3', '1510'); +insert into sys_role_menu values ('3', '1511'); +insert into sys_role_menu values ('4', '5'); +insert into sys_role_menu values ('4', '1500'); +insert into sys_role_menu values ('4', '1501'); +insert into sys_role_menu values ('4', '1502'); +insert into sys_role_menu values ('4', '1503'); +insert into sys_role_menu values ('4', '1504'); +insert into sys_role_menu values ('4', '1505'); +insert into sys_role_menu values ('4', '1506'); +insert into sys_role_menu values ('4', '1507'); +insert into sys_role_menu values ('4', '1508'); +insert into sys_role_menu values ('4', '1509'); +insert into sys_role_menu values ('4', '1510'); +insert into sys_role_menu values ('4', '1511'); -- ---------------------------- -- 8、角色和部门关联表 角色1-N部门 -- ---------------------------- -drop table if exists sys_role_dept; create table sys_role_dept ( role_id bigint(20) not null comment '角色ID', dept_id bigint(20) not null comment '部门ID', primary key(role_id, dept_id) ) engine=innodb comment = '角色和部门关联表'; --- ---------------------------- --- 初始化-角色和部门关联表数据 --- ---------------------------- -insert into sys_role_dept values ('2', '100'); -insert into sys_role_dept values ('2', '101'); -insert into sys_role_dept values ('2', '105'); - - -- ---------------------------- -- 9、用户与岗位关联表 用户1-N岗位 -- ---------------------------- -drop table if exists sys_user_post; create table sys_user_post ( user_id bigint(20) not null comment '用户ID', @@ -542,13 +537,10 @@ create table sys_user_post -- 初始化-用户与岗位关联表数据 -- ---------------------------- insert into sys_user_post values ('1', '1'); -insert into sys_user_post values ('2', '2'); - -- ---------------------------- -- 10、操作日志记录 -- ---------------------------- -drop table if exists sys_oper_log; create table sys_oper_log ( oper_id bigint(20) not null comment '日志主键', tenant_id varchar(20) default '000000' comment '租户编号', @@ -578,7 +570,6 @@ create table sys_oper_log ( -- ---------------------------- -- 11、字典类型表 -- ---------------------------- -drop table if exists sys_dict_type; create table sys_dict_type ( dict_id bigint(20) not null comment '字典主键', @@ -610,7 +601,6 @@ insert into sys_dict_type values(12, '000000', '设备类型', 'sys_device_type' -- ---------------------------- -- 12、字典数据表 -- ---------------------------- -drop table if exists sys_dict_data; create table sys_dict_data ( dict_code bigint(20) not null comment '字典编码', @@ -670,7 +660,6 @@ insert into sys_dict_data values(38, '000000', 0, '小程序', 'xcx', 'sy -- ---------------------------- -- 13、参数配置表 -- ---------------------------- -drop table if exists sys_config; create table sys_config ( config_id bigint(20) not null comment '参数主键', tenant_id varchar(20) default '000000' comment '租户编号', @@ -697,7 +686,6 @@ insert into sys_config values(11, '000000', 'OSS预览列表资源开关', -- ---------------------------- -- 14、系统访问记录 -- ---------------------------- -drop table if exists sys_logininfor; create table sys_logininfor ( info_id bigint(20) not null comment '访问ID', tenant_id varchar(20) default '000000' comment '租户编号', @@ -720,7 +708,6 @@ create table sys_logininfor ( -- ---------------------------- -- 17、通知公告表 -- ---------------------------- -drop table if exists sys_notice; create table sys_notice ( notice_id bigint(20) not null comment '公告ID', tenant_id varchar(20) default '000000' comment '租户编号', @@ -747,7 +734,6 @@ insert into sys_notice values('2', '000000', '维护通知:2018-07-01 系统 -- ---------------------------- -- 18、代码生成业务表 -- ---------------------------- -drop table if exists gen_table; create table gen_table ( table_id bigint(20) not null comment '编号', data_name varchar(200) default '' comment '数据源名称', @@ -778,7 +764,6 @@ create table gen_table ( -- ---------------------------- -- 19、代码生成业务表字段 -- ---------------------------- -drop table if exists gen_table_column; create table gen_table_column ( column_id bigint(20) not null comment '编号', table_id bigint(20) comment '归属表编号', @@ -809,7 +794,6 @@ create table gen_table_column ( -- ---------------------------- -- OSS对象存储表 -- ---------------------------- -drop table if exists sys_oss; create table sys_oss ( oss_id bigint(20) not null comment '对象存储主键', tenant_id varchar(20) default '000000' comment '租户编号', @@ -829,7 +813,6 @@ create table sys_oss ( -- ---------------------------- -- OSS对象存储动态配置表 -- ---------------------------- -drop table if exists sys_oss_config; create table sys_oss_config ( oss_config_id bigint(20) not null comment '主建', tenant_id varchar(20) default '000000'comment '租户编号', @@ -863,7 +846,6 @@ insert into sys_oss_config values (5, '000000', 'image', 'ruoyi', 'r -- ---------------------------- -- 系统授权表 -- ---------------------------- -drop table if exists sys_client; create table sys_client ( id bigint(20) not null comment 'id', client_id varchar(64) default null comment '客户端id', @@ -885,3 +867,69 @@ create table sys_client ( insert into sys_client values (1, 'e5cd7e4891bf95d1d19206ce24a7b32e', 'pc', 'pc123', 'password,social', 'pc', 1800, 604800, 0, 0, 103, 1, sysdate(), 1, sysdate()); insert into sys_client values (2, '428a8310cd442757ae699df5d894f051', 'app', 'app123', 'password,sms,social', 'android', 1800, 604800, 0, 0, 103, 1, sysdate(), 1, sysdate()); + + +CREATE TABLE test_demo +( + id bigint(0) NOT NULL COMMENT '主键', + tenant_id varchar(20) NULL DEFAULT '000000' COMMENT '租户编号', + dept_id bigint(0) NULL DEFAULT NULL COMMENT '部门id', + user_id bigint(0) NULL DEFAULT NULL COMMENT '用户id', + order_num int(0) NULL DEFAULT 0 COMMENT '排序号', + test_key varchar(255) NULL DEFAULT NULL COMMENT 'key键', + value varchar(255) NULL DEFAULT NULL COMMENT '值', + version int(0) NULL DEFAULT 0 COMMENT '版本', + create_dept bigint(0) NULL DEFAULT NULL COMMENT '创建部门', + create_time datetime(0) NULL DEFAULT NULL COMMENT '创建时间', + create_by bigint(0) NULL DEFAULT NULL COMMENT '创建人', + update_time datetime(0) NULL DEFAULT NULL COMMENT '更新时间', + update_by bigint(0) NULL DEFAULT NULL COMMENT '更新人', + del_flag int(0) NULL DEFAULT 0 COMMENT '删除标志', + PRIMARY KEY (id) USING BTREE +) ENGINE = InnoDB COMMENT = '测试单表'; + +CREATE TABLE test_tree +( + id bigint(0) NOT NULL COMMENT '主键', + tenant_id varchar(20) NULL DEFAULT '000000' COMMENT '租户编号', + parent_id bigint(0) NULL DEFAULT 0 COMMENT '父id', + dept_id bigint(0) NULL DEFAULT NULL COMMENT '部门id', + user_id bigint(0) NULL DEFAULT NULL COMMENT '用户id', + tree_name varchar(255) NULL DEFAULT NULL COMMENT '值', + version int(0) NULL DEFAULT 0 COMMENT '版本', + create_dept bigint(0) NULL DEFAULT NULL COMMENT '创建部门', + create_time datetime(0) NULL DEFAULT NULL COMMENT '创建时间', + create_by bigint(0) NULL DEFAULT NULL COMMENT '创建人', + update_time datetime(0) NULL DEFAULT NULL COMMENT '更新时间', + update_by bigint(0) NULL DEFAULT NULL COMMENT '更新人', + del_flag int(0) NULL DEFAULT 0 COMMENT '删除标志', + PRIMARY KEY (id) USING BTREE +) ENGINE = InnoDB COMMENT = '测试树表'; + +INSERT INTO test_demo VALUES (1, '000000', 102, 4, 1, '测试数据权限', '测试', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (2, '000000', 102, 3, 2, '子节点1', '111', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (3, '000000', 102, 3, 3, '子节点2', '222', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (4, '000000', 108, 4, 4, '测试数据', 'demo', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (5, '000000', 108, 3, 13, '子节点11', '1111', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (6, '000000', 108, 3, 12, '子节点22', '2222', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (7, '000000', 108, 3, 11, '子节点33', '3333', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (8, '000000', 108, 3, 10, '子节点44', '4444', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (9, '000000', 108, 3, 9, '子节点55', '5555', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (10, '000000', 108, 3, 8, '子节点66', '6666', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (11, '000000', 108, 3, 7, '子节点77', '7777', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (12, '000000', 108, 3, 6, '子节点88', '8888', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (13, '000000', 108, 3, 5, '子节点99', '9999', 0, 103, sysdate(), 1, NULL, NULL, 0); + +INSERT INTO test_tree VALUES (1, '000000', 0, 102, 4, '测试数据权限', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (2, '000000', 1, 102, 3, '子节点1', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (3, '000000', 2, 102, 3, '子节点2', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (4, '000000', 0, 108, 4, '测试树1', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (5, '000000', 4, 108, 3, '子节点11', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (6, '000000', 4, 108, 3, '子节点22', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (7, '000000', 4, 108, 3, '子节点33', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (8, '000000', 5, 108, 3, '子节点44', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (9, '000000', 6, 108, 3, '子节点55', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (10, '000000', 7, 108, 3, '子节点66', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (11, '000000', 7, 108, 3, '子节点77', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (12, '000000', 10, 108, 3, '子节点88', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (13, '000000', 10, 108, 3, '子节点99', 0, 103, sysdate(), 1, NULL, NULL, 0); diff --git a/script/sql/sqlserver/easy_retry_sqlserver.sql b/script/sql/sqlserver/easy_retry_sqlserver.sql new file mode 100644 index 000000000..da22b5f56 --- /dev/null +++ b/script/sql/sqlserver/easy_retry_sqlserver.sql @@ -0,0 +1,2749 @@ +-- er_distributed_lock +CREATE TABLE er_distributed_lock +( + id bigint PRIMARY KEY IDENTITY, + name nvarchar(64) NOT NULL, + lock_until datetime2 NOT NULL DEFAULT GETDATE(), + locked_at datetime2 NOT NULL DEFAULT GETDATE(), + locked_by nvarchar(255) NOT NULL, + create_dt datetime2 NOT NULL DEFAULT GETDATE(), + update_dt datetime2 NOT NULL DEFAULT GETDATE() +) +GO + +CREATE UNIQUE NONCLUSTERED INDEX uk_name ON er_distributed_lock (name ASC) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'er_distributed_lock', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'锁名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_distributed_lock', + 'COLUMN', N'name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'锁定时长', + 'SCHEMA', N'dbo', + 'TABLE', N'er_distributed_lock', + 'COLUMN', N'lock_until' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'锁定时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_distributed_lock', + 'COLUMN', N'locked_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'锁定者', + 'SCHEMA', N'dbo', + 'TABLE', N'er_distributed_lock', + 'COLUMN', N'locked_by' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_distributed_lock', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_distributed_lock', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'锁定表', + 'SCHEMA', N'dbo', + 'TABLE', N'er_distributed_lock' +GO + +-- er_group_config +CREATE TABLE er_group_config +( + id bigint PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL DEFAULT '', + description nvarchar(256) NOT NULL DEFAULT '', + token nvarchar(64) NOT NULL DEFAULT 'ER_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', + group_status tinyint NOT NULL DEFAULT '0', + version int NOT NULL, + group_partition int NOT NULL, + id_generator_mode tinyint NOT NULL DEFAULT '1', + init_scene tinyint NOT NULL DEFAULT '0', + bucket_index int NOT NULL DEFAULT '0', + create_dt datetime2 NOT NULL DEFAULT GETDATE(), + update_dt datetime2 NOT NULL DEFAULT GETDATE() +) +GO + +CREATE UNIQUE NONCLUSTERED INDEX uk_namespace_id_group_name ON er_group_config (namespace_id ASC, group_name ASC) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'er_group_config', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_group_config', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_group_config', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组描述', + 'SCHEMA', N'dbo', + 'TABLE', N'er_group_config', + 'COLUMN', N'description' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'token', + 'SCHEMA', N'dbo', + 'TABLE', N'er_group_config', + 'COLUMN', N'token' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组状态 0、未启用 1、启用', + 'SCHEMA', N'dbo', + 'TABLE', N'er_group_config', + 'COLUMN', N'group_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'版本号', + 'SCHEMA', N'dbo', + 'TABLE', N'er_group_config', + 'COLUMN', N'version' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'分区', + 'SCHEMA', N'dbo', + 'TABLE', N'er_group_config', + 'COLUMN', N'group_partition' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'唯一id生成模式 默认号段模式', + 'SCHEMA', N'dbo', + 'TABLE', N'er_group_config', + 'COLUMN', N'id_generator_mode' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否初始化场景 0:否 1:是', + 'SCHEMA', N'dbo', + 'TABLE', N'er_group_config', + 'COLUMN', N'init_scene' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'bucket', + 'SCHEMA', N'dbo', + 'TABLE', N'er_group_config', + 'COLUMN', N'bucket_index' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_group_config', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_group_config', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组配置', + 'SCHEMA', N'dbo', + 'TABLE', N'er_group_config' +GO + +INSERT INTO er_group_config(namespace_id, group_name, description, token, group_status, version, group_partition, id_generator_mode, init_scene, bucket_index, create_dt, update_dt) VALUES (N'dev', N'ruoyi_group', N'', N'ER_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', N'1', N'1', N'0', N'1', N'1', N'4', getdate(), getdate()); +GO + +-- er_job +CREATE TABLE er_job +( + id bigint PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + job_name nvarchar(64) NOT NULL, + args_str nvarchar(max) NULL, + args_type tinyint NOT NULL DEFAULT '1', + next_trigger_at bigint NOT NULL, + job_status tinyint NOT NULL DEFAULT '1', + task_type tinyint NOT NULL DEFAULT '1', + route_key tinyint NOT NULL DEFAULT '4', + executor_type tinyint NOT NULL DEFAULT '1', + executor_info nvarchar(255) NULL DEFAULT '', + trigger_type tinyint NOT NULL, + trigger_interval nvarchar(255) NOT NULL, + block_strategy tinyint NOT NULL DEFAULT '1', + executor_timeout int NOT NULL DEFAULT '0', + max_retry_times int NOT NULL DEFAULT '0', + parallel_num int NOT NULL DEFAULT '1', + retry_interval int NOT NULL DEFAULT '0', + bucket_index int NOT NULL DEFAULT '0', + resident tinyint NOT NULL DEFAULT '0', + description nvarchar(256) NOT NULL DEFAULT '', + ext_attrs nvarchar(256) NULL DEFAULT '', + create_dt datetime2 DEFAULT GETDATE(), + update_dt datetime2 DEFAULT GETDATE(), + deleted BIT NOT NULL DEFAULT 0 +) +GO + +CREATE NONCLUSTERED INDEX idx_namespace_id_group_name ON er_job (namespace_id ASC, group_name ASC) +GO +CREATE NONCLUSTERED INDEX idx_job_status_bucket_index ON er_job (job_status ASC, bucket_index ASC) +GO +CREATE NONCLUSTERED INDEX idx_create_dt ON er_job (create_dt ASC) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job', + 'COLUMN', N'job_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行方法参数', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job', + 'COLUMN', N'args_str' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'参数类型 ', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job', + 'COLUMN', N'args_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'下次触发时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job', + 'COLUMN', N'next_trigger_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务状态 0、关闭、1、开启', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job', + 'COLUMN', N'job_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务类型 1、集群 2、广播 3、切片', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job', + 'COLUMN', N'task_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'路由策略', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job', + 'COLUMN', N'route_key' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行器类型', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job', + 'COLUMN', N'executor_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行器名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job', + 'COLUMN', N'executor_info' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'触发类型 1.CRON 表达式 2. 固定时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job', + 'COLUMN', N'trigger_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'间隔时长', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job', + 'COLUMN', N'trigger_interval' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'阻塞策略 1、丢弃 2、覆盖 3、并行', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job', + 'COLUMN', N'block_strategy' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务执行超时时间,单位秒', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job', + 'COLUMN', N'executor_timeout' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'最大重试次数', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job', + 'COLUMN', N'max_retry_times' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'并行数', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job', + 'COLUMN', N'parallel_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试间隔(s)', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job', + 'COLUMN', N'retry_interval' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'bucket', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job', + 'COLUMN', N'bucket_index' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否是常驻任务', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job', + 'COLUMN', N'resident' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'描述', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job', + 'COLUMN', N'description' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'逻辑删除 1、删除', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务信息', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job' +GO + + +-- er_job_log_message +CREATE TABLE er_job_log_message +( + id bigint PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + job_id bigint NOT NULL, + task_batch_id bigint NOT NULL, + task_id bigint NOT NULL, + message nvarchar(max) NOT NULL, + log_num int NOT NULL DEFAULT '1', + real_time bigint NOT NULL DEFAULT '0', + create_dt datetime2 NOT NULL DEFAULT GETDATE(), + ext_attrs nvarchar(256) NULL DEFAULT '' +) +GO + +CREATE NONCLUSTERED INDEX idx_task_batch_id_task_id ON er_job_log_message (task_batch_id ASC, task_id ASC) +GO +CREATE NONCLUSTERED INDEX idx_create_dt ON er_job_log_message (create_dt ASC) +GO +CREATE NONCLUSTERED INDEX idx_namespace_id_group_name ON er_job_log_message (namespace_id ASC, group_name ASC) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_log_message', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_log_message', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_log_message', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务信息id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_log_message', + 'COLUMN', N'job_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务批次id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_log_message', + 'COLUMN', N'task_batch_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'调度任务id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_log_message', + 'COLUMN', N'task_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'调度信息', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_log_message', + 'COLUMN', N'message' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_log_message', + 'COLUMN', N'log_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'上报时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_log_message', + 'COLUMN', N'real_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_log_message', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_log_message', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'调度日志', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_log_message' +GO + + +-- er_job_notify_config +CREATE TABLE er_job_notify_config +( + id bigint PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + job_id bigint NOT NULL, + notify_status tinyint NOT NULL DEFAULT '0', + notify_type tinyint NOT NULL DEFAULT '0', + notify_attribute nvarchar(512) NOT NULL, + notify_threshold int NOT NULL DEFAULT '0', + notify_scene tinyint NOT NULL DEFAULT '0', + rate_limiter_status tinyint NOT NULL DEFAULT '0', + rate_limiter_threshold int NOT NULL DEFAULT '0', + description nvarchar(256) NOT NULL DEFAULT '', + create_dt datetime2 NOT NULL DEFAULT GETDATE(), + update_dt datetime2 NOT NULL DEFAULT GETDATE() +) +GO + +CREATE NONCLUSTERED INDEX idx_namespace_id_group_name_job_id ON er_job_notify_config (namespace_id ASC, group_name ASC, job_id ASC) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_notify_config', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_notify_config', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_notify_config', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_notify_config', + 'COLUMN', N'job_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知状态 0、未启用 1、启用', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_notify_config', + 'COLUMN', N'notify_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知类型 1、钉钉 2、邮件 3、企业微信', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_notify_config', + 'COLUMN', N'notify_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'配置属性', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_notify_config', + 'COLUMN', N'notify_attribute' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知阈值', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_notify_config', + 'COLUMN', N'notify_threshold' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知场景', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_notify_config', + 'COLUMN', N'notify_scene' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'限流状态 0、未启用 1、启用', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_notify_config', + 'COLUMN', N'rate_limiter_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'每秒限流阈值', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_notify_config', + 'COLUMN', N'rate_limiter_threshold' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'描述', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_notify_config', + 'COLUMN', N'description' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_notify_config', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_notify_config', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'job通知配置', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_notify_config' +GO + + +-- er_job_summary +CREATE TABLE er_job_summary +( + id bigint PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + business_id bigint NOT NULL, + system_task_type tinyint NOT NULL DEFAULT '3', + trigger_at datetime2 NOT NULL, + success_num int NOT NULL DEFAULT '0', + fail_num int NOT NULL DEFAULT '0', + fail_reason nvarchar(512) NOT NULL DEFAULT '', + stop_num int NOT NULL DEFAULT '0', + stop_reason nvarchar(512) NOT NULL DEFAULT '', + cancel_num int NOT NULL DEFAULT '0', + cancel_reason nvarchar(512) NOT NULL DEFAULT '', + create_dt datetime2 NOT NULL DEFAULT GETDATE(), + update_dt datetime2 NOT NULL DEFAULT GETDATE() +) +GO + +CREATE UNIQUE NONCLUSTERED INDEX uk_trigger_at_system_task_type_business_id ON er_job_summary (trigger_at ASC, system_task_type ASC, business_id ASC) +GO +CREATE NONCLUSTERED INDEX idx_namespace_id_group_name_business_id ON er_job_summary (namespace_id ASC, group_name ASC, business_id ASC) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_summary', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_summary', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_summary', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'业务id (job_id或workflow_id)', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_summary', + 'COLUMN', N'business_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务类型 3、JOB任务 4、WORKFLOW任务', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_summary', + 'COLUMN', N'system_task_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'统计时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_summary', + 'COLUMN', N'trigger_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行成功-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_summary', + 'COLUMN', N'success_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行失败-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_summary', + 'COLUMN', N'fail_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'失败原因', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_summary', + 'COLUMN', N'fail_reason' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行失败-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_summary', + 'COLUMN', N'stop_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'失败原因', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_summary', + 'COLUMN', N'stop_reason' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行失败-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_summary', + 'COLUMN', N'cancel_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'失败原因', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_summary', + 'COLUMN', N'cancel_reason' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_summary', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_summary', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'DashBoard_Job', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_summary' +GO + + +-- er_job_task +CREATE TABLE er_job_task +( + id bigint PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + job_id bigint NOT NULL, + task_batch_id bigint NOT NULL, + parent_id bigint NOT NULL DEFAULT '0', + task_status tinyint NOT NULL DEFAULT '0', + retry_count int NOT NULL DEFAULT '0', + client_info nvarchar(128) NULL, + result_message nvarchar(max) NOT NULL, + args_str nvarchar(max) NULL, + args_type tinyint NOT NULL DEFAULT '1', + ext_attrs nvarchar(256) NULL DEFAULT '', + create_dt datetime2 NOT NULL DEFAULT GETDATE(), + update_dt datetime2 NOT NULL DEFAULT GETDATE() +) +GO + +CREATE NONCLUSTERED INDEX idx_task_batch_id_task_status ON er_job_task (task_batch_id ASC, task_status ASC) +GO +CREATE NONCLUSTERED INDEX idx_create_dt ON er_job_task (create_dt ASC) +GO +CREATE NONCLUSTERED INDEX idx_namespace_id_group_name ON er_job_task (namespace_id ASC, group_name ASC) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务信息id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task', + 'COLUMN', N'job_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'调度任务id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task', + 'COLUMN', N'task_batch_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'父执行器id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task', + 'COLUMN', N'parent_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行的状态 0、失败 1、成功', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task', + 'COLUMN', N'task_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试次数', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task', + 'COLUMN', N'retry_count' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'客户端地址 clientId#ip:port', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task', + 'COLUMN', N'client_info' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行结果', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task', + 'COLUMN', N'result_message' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行方法参数', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task', + 'COLUMN', N'args_str' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'参数类型 ', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task', + 'COLUMN', N'args_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务实例', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task' +GO + +-- er_job_task_batch +CREATE TABLE er_job_task_batch +( + id bigint PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + job_id bigint NOT NULL, + workflow_node_id bigint NOT NULL DEFAULT '0', + parent_workflow_node_id bigint NOT NULL DEFAULT '0', + workflow_task_batch_id bigint NOT NULL DEFAULT '0', + task_batch_status tinyint NOT NULL DEFAULT '0', + operation_reason tinyint NOT NULL DEFAULT '0', + execution_at bigint NOT NULL DEFAULT '0', + system_task_type tinyint NOT NULL DEFAULT '3', + parent_id nvarchar(64) NOT NULL DEFAULT '', + create_dt datetime2 NOT NULL DEFAULT GETDATE(), + update_dt datetime2 NOT NULL DEFAULT GETDATE(), + deleted BIT DEFAULT 0, + ext_attrs nvarchar(256) NULL DEFAULT '' +) +GO + +CREATE NONCLUSTERED INDEX idx_job_id_task_batch_status ON er_job_task_batch (job_id ASC, task_batch_status ASC) +GO +CREATE NONCLUSTERED INDEX idx_create_dt ON er_job_task_batch (create_dt ASC) +GO +CREATE NONCLUSTERED INDEX idx_namespace_id_group_name ON er_job_task_batch (namespace_id ASC, group_name ASC) +GO +CREATE NONCLUSTERED INDEX idx_workflow_task_batch_id_workflow_node_id ON er_job_task_batch (workflow_task_batch_id ASC, workflow_node_id ASC) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task_batch', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task_batch', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task_batch', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task_batch', + 'COLUMN', N'job_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流节点id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task_batch', + 'COLUMN', N'workflow_node_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流任务父批次id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task_batch', + 'COLUMN', N'parent_workflow_node_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流任务批次id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task_batch', + 'COLUMN', N'workflow_task_batch_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务批次状态 0、失败 1、成功', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task_batch', + 'COLUMN', N'task_batch_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'操作原因', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task_batch', + 'COLUMN', N'operation_reason' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务执行时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task_batch', + 'COLUMN', N'execution_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务类型 3、JOB任务 4、WORKFLOW任务', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task_batch', + 'COLUMN', N'system_task_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'父节点', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task_batch', + 'COLUMN', N'parent_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task_batch', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task_batch', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'逻辑删除 1、删除', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task_batch', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task_batch', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务批次', + 'SCHEMA', N'dbo', + 'TABLE', N'er_job_task_batch' +GO + +-- er_namespace +CREATE TABLE er_namespace +( + id bigint PRIMARY KEY IDENTITY, + name nvarchar(64) NOT NULL, + unique_id nvarchar(64) NOT NULL, + description nvarchar(256) NOT NULL DEFAULT '', + create_dt datetime2 NOT NULL DEFAULT GETDATE(), + update_dt datetime2 NOT NULL DEFAULT GETDATE(), + deleted BIT NOT NULL DEFAULT 0 +) +GO + +CREATE UNIQUE NONCLUSTERED INDEX uk_unique_id ON er_namespace (unique_id ASC) +GO +CREATE NONCLUSTERED INDEX idx_name ON er_namespace (name ASC) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'er_namespace', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_namespace', + 'COLUMN', N'name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'唯一id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_namespace', + 'COLUMN', N'unique_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'描述', + 'SCHEMA', N'dbo', + 'TABLE', N'er_namespace', + 'COLUMN', N'description' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_namespace', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_namespace', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'逻辑删除 1、删除', + 'SCHEMA', N'dbo', + 'TABLE', N'er_namespace', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_namespace' +GO + +INSERT INTO er_namespace(name, unique_id, description, create_dt, update_dt, deleted) VALUES (N'Development', N'dev', N'', getdate(), getdate(), N'0'); +INSERT INTO er_namespace(name, unique_id, description, create_dt, update_dt, deleted) VALUES (N'Production', N'prod', N'', getdate(), getdate(), N'0'); +GO + +-- er_notify_config +CREATE TABLE er_notify_config +( + id bigint PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + scene_name nvarchar(64) NOT NULL, + notify_status tinyint NOT NULL DEFAULT '0', + notify_type tinyint NOT NULL DEFAULT '0', + notify_attribute nvarchar(512) NOT NULL, + notify_threshold int NOT NULL DEFAULT '0', + notify_scene tinyint NOT NULL DEFAULT '0', + rate_limiter_status tinyint NOT NULL DEFAULT '0', + rate_limiter_threshold int NOT NULL DEFAULT '0', + description nvarchar(256) NOT NULL DEFAULT '', + create_dt datetime2 NOT NULL DEFAULT GETDATE(), + update_dt datetime2 NOT NULL DEFAULT GETDATE() +) +GO + +CREATE NONCLUSTERED INDEX idx_namespace_id_group_name_scene_name ON er_notify_config (namespace_id ASC, group_name ASC, scene_name ASC) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'er_notify_config', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_notify_config', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_notify_config', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'场景名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_notify_config', + 'COLUMN', N'scene_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知状态 0、未启用 1、启用', + 'SCHEMA', N'dbo', + 'TABLE', N'er_notify_config', + 'COLUMN', N'notify_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知类型 1、钉钉 2、邮件 3、企业微信', + 'SCHEMA', N'dbo', + 'TABLE', N'er_notify_config', + 'COLUMN', N'notify_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'配置属性', + 'SCHEMA', N'dbo', + 'TABLE', N'er_notify_config', + 'COLUMN', N'notify_attribute' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知阈值', + 'SCHEMA', N'dbo', + 'TABLE', N'er_notify_config', + 'COLUMN', N'notify_threshold' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知场景', + 'SCHEMA', N'dbo', + 'TABLE', N'er_notify_config', + 'COLUMN', N'notify_scene' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'限流状态 0、未启用 1、启用', + 'SCHEMA', N'dbo', + 'TABLE', N'er_notify_config', + 'COLUMN', N'rate_limiter_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'每秒限流阈值', + 'SCHEMA', N'dbo', + 'TABLE', N'er_notify_config', + 'COLUMN', N'rate_limiter_threshold' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'描述', + 'SCHEMA', N'dbo', + 'TABLE', N'er_notify_config', + 'COLUMN', N'description' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_notify_config', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_notify_config', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知配置', + 'SCHEMA', N'dbo', + 'TABLE', N'er_notify_config' +GO + +-- er_retry_dead_letter_0 +CREATE TABLE er_retry_dead_letter_0 +( + id bigint PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + unique_id nvarchar(64) NOT NULL, + group_name nvarchar(64) NOT NULL, + scene_name nvarchar(64) NOT NULL, + idempotent_id nvarchar(64) NOT NULL, + biz_no nvarchar(64) NOT NULL DEFAULT '', + executor_name nvarchar(512) NOT NULL DEFAULT '', + args_str nvarchar(max) NOT NULL, + ext_attrs nvarchar(max) NOT NULL, + task_type tinyint NOT NULL DEFAULT '1', + create_dt datetime2 NOT NULL DEFAULT GETDATE() +) +GO + +CREATE UNIQUE NONCLUSTERED INDEX uk_namespace_id_group_name_unique_id ON er_retry_dead_letter_0 (namespace_id ASC, group_name ASC, unique_id ASC) +GO +CREATE NONCLUSTERED INDEX idx_namespace_id_group_name_scene_name ON er_retry_dead_letter_0 (namespace_id ASC, group_name ASC, scene_name ASC) +GO +CREATE NONCLUSTERED INDEX idx_idempotent_id ON er_retry_dead_letter_0 (idempotent_id ASC) +GO +CREATE NONCLUSTERED INDEX idx_biz_no ON er_retry_dead_letter_0 (biz_no ASC) +GO +CREATE NONCLUSTERED INDEX idx_create_dt ON er_retry_dead_letter_0 (create_dt ASC) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_dead_letter_0', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_dead_letter_0', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'同组下id唯一', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_dead_letter_0', + 'COLUMN', N'unique_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_dead_letter_0', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'场景名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_dead_letter_0', + 'COLUMN', N'scene_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'幂等id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_dead_letter_0', + 'COLUMN', N'idempotent_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'业务编号', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_dead_letter_0', + 'COLUMN', N'biz_no' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行器名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_dead_letter_0', + 'COLUMN', N'executor_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行方法参数', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_dead_letter_0', + 'COLUMN', N'args_str' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_dead_letter_0', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务类型 1、重试数据 2、回调数据', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_dead_letter_0', + 'COLUMN', N'task_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_dead_letter_0', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'死信队列表', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_dead_letter_0' +GO + + +-- er_retry_summary +CREATE TABLE er_retry_summary +( + id bigint PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL DEFAULT '', + scene_name nvarchar(50) NOT NULL DEFAULT '', + trigger_at datetime2 NOT NULL DEFAULT GETDATE(), + running_num int NOT NULL DEFAULT '0', + finish_num int NOT NULL DEFAULT '0', + max_count_num int NOT NULL DEFAULT '0', + suspend_num int NOT NULL DEFAULT '0', + create_dt datetime2 NOT NULL DEFAULT GETDATE(), + update_dt datetime2 NOT NULL DEFAULT GETDATE() +) +GO + +CREATE UNIQUE NONCLUSTERED INDEX uk_scene_name_trigger_at ON er_retry_summary (namespace_id ASC, group_name ASC, + scene_name ASC, trigger_at ASC) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_summary', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_summary', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_summary', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'场景名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_summary', + 'COLUMN', N'scene_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'统计时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_summary', + 'COLUMN', N'trigger_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试中-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_summary', + 'COLUMN', N'running_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试完成-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_summary', + 'COLUMN', N'finish_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试到达最大次数-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_summary', + 'COLUMN', N'max_count_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'暂停重试-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_summary', + 'COLUMN', N'suspend_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_summary', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_summary', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'DashBoard_Retry', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_summary' +GO + +-- er_retry_task_0 +CREATE TABLE er_retry_task_0 +( + id bigint PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + unique_id nvarchar(64) NOT NULL, + group_name nvarchar(64) NOT NULL, + scene_name nvarchar(64) NOT NULL, + idempotent_id nvarchar(64) NOT NULL, + biz_no nvarchar(64) NOT NULL DEFAULT '', + executor_name nvarchar(512) NOT NULL DEFAULT '', + args_str nvarchar(max) NOT NULL, + ext_attrs nvarchar(max) NOT NULL, + next_trigger_at datetime2 NOT NULL, + retry_count int NOT NULL DEFAULT '0', + retry_status tinyint NOT NULL DEFAULT '0', + task_type tinyint NOT NULL DEFAULT '1', + create_dt datetime2 NOT NULL DEFAULT GETDATE(), + update_dt datetime2 NOT NULL DEFAULT GETDATE() +) +GO + +CREATE UNIQUE NONCLUSTERED INDEX uk_name_unique_id ON er_retry_task_0 (namespace_id ASC, group_name ASC, unique_id ASC) +GO +CREATE NONCLUSTERED INDEX idx_namespace_id_group_name_scene_name ON er_retry_task_0 (namespace_id ASC, group_name ASC, scene_name ASC) +GO +CREATE NONCLUSTERED INDEX idx_namespace_id_group_name_task_type ON er_retry_task_0 (namespace_id ASC, group_name ASC, task_type ASC) +GO +CREATE NONCLUSTERED INDEX idx_namespace_id_group_name_retry_status ON er_retry_task_0 (namespace_id ASC, group_name ASC, retry_status ASC) +GO +CREATE NONCLUSTERED INDEX idx_idempotent_id ON er_retry_task_0 (idempotent_id ASC) +GO +CREATE NONCLUSTERED INDEX idx_biz_no ON er_retry_task_0 (biz_no ASC) +GO +CREATE NONCLUSTERED INDEX idx_create_dt ON er_retry_task_0 (create_dt ASC) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_0', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_0', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'同组下id唯一', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_0', + 'COLUMN', N'unique_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_0', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'场景名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_0', + 'COLUMN', N'scene_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'幂等id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_0', + 'COLUMN', N'idempotent_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'业务编号', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_0', + 'COLUMN', N'biz_no' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行器名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_0', + 'COLUMN', N'executor_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行方法参数', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_0', + 'COLUMN', N'args_str' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_0', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'下次触发时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_0', + 'COLUMN', N'next_trigger_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试次数', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_0', + 'COLUMN', N'retry_count' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试状态 0、重试中 1、成功 2、最大重试次数', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_0', + 'COLUMN', N'retry_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务类型 1、重试数据 2、回调数据', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_0', + 'COLUMN', N'task_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_0', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_0', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务表', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_0' +GO + +-- er_retry_task_log +CREATE TABLE er_retry_task_log +( + id bigint PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + unique_id nvarchar(64) NOT NULL, + group_name nvarchar(64) NOT NULL, + scene_name nvarchar(64) NOT NULL, + idempotent_id nvarchar(64) NOT NULL, + biz_no nvarchar(64) NOT NULL DEFAULT '', + executor_name nvarchar(512) NOT NULL DEFAULT '', + args_str nvarchar(max) NOT NULL, + ext_attrs nvarchar(max) NOT NULL, + retry_status tinyint NOT NULL DEFAULT '0', + task_type tinyint NOT NULL DEFAULT '1', + create_dt datetime2 NOT NULL DEFAULT GETDATE(), + update_dt datetime2 NOT NULL DEFAULT GETDATE() +) +GO + +CREATE NONCLUSTERED INDEX idx_group_name_scene_name ON er_retry_task_log (namespace_id ASC, group_name ASC, scene_name ASC) +GO +CREATE NONCLUSTERED INDEX idx_retry_status ON er_retry_task_log (retry_status ASC) +GO +CREATE NONCLUSTERED INDEX idx_idempotent_id ON er_retry_task_log (idempotent_id ASC) +GO +CREATE NONCLUSTERED INDEX idx_unique_id ON er_retry_task_log (unique_id ASC) +GO +CREATE NONCLUSTERED INDEX idx_biz_no ON er_retry_task_log (biz_no ASC) +GO +CREATE NONCLUSTERED INDEX idx_create_dt ON er_retry_task_log (create_dt ASC) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_log', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_log', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'同组下id唯一', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_log', + 'COLUMN', N'unique_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_log', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'场景名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_log', + 'COLUMN', N'scene_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'幂等id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_log', + 'COLUMN', N'idempotent_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'业务编号', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_log', + 'COLUMN', N'biz_no' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行器名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_log', + 'COLUMN', N'executor_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行方法参数', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_log', + 'COLUMN', N'args_str' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_log', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试状态 0、重试中 1、成功 2、最大次数', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_log', + 'COLUMN', N'retry_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务类型 1、重试数据 2、回调数据', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_log', + 'COLUMN', N'task_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_log', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_log', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务日志基础信息表', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_log' +GO + +-- er_retry_task_log_message +CREATE TABLE er_retry_task_log_message +( + id bigint PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + unique_id nvarchar(64) NOT NULL, + create_dt datetime2 NOT NULL DEFAULT GETDATE(), + message nvarchar(max) NOT NULL, + log_num int NOT NULL DEFAULT 1, + real_time bigint NOT NULL DEFAULT 0 +) +GO + +CREATE NONCLUSTERED INDEX idx_namespace_id_group_name_scene_name ON er_retry_task_log_message (namespace_id ASC, group_name ASC, unique_id ASC) +GO +CREATE NONCLUSTERED INDEX idx_create_dt ON er_retry_task_log_message (create_dt ASC) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_log_message', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_log_message', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_log_message', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'同组下id唯一', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_log_message', + 'COLUMN', N'unique_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_log_message', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'异常信息', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_log_message', + 'COLUMN', N'message' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_log_message', + 'COLUMN', N'log_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'上报时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_log_message', + 'COLUMN', N'real_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务调度日志信息记录表', + 'SCHEMA', N'dbo', + 'TABLE', N'er_retry_task_log_message' +GO + +-- er_scene_config +CREATE TABLE er_scene_config +( + id bigint IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + scene_name nvarchar(64) NOT NULL, + group_name nvarchar(64) NOT NULL, + scene_status tinyint NOT NULL DEFAULT '0', + max_retry_count int NOT NULL DEFAULT '5', + back_off tinyint NOT NULL DEFAULT '1', + trigger_interval nvarchar(16) NOT NULL DEFAULT '', + deadline_request bigint NOT NULL DEFAULT '60000', + executor_timeout int NOT NULL DEFAULT '5', + route_key tinyint NOT NULL DEFAULT '4', + description nvarchar(256) NOT NULL DEFAULT '', + create_dt datetime2 NOT NULL DEFAULT GETDATE(), + update_dt datetime2 NOT NULL DEFAULT GETDATE() +) +GO + +CREATE UNIQUE NONCLUSTERED INDEX uk_namespace_id_group_name_scene_name ON er_scene_config (namespace_id ASC, group_name ASC, scene_name ASC) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'er_scene_config', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_scene_config', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'场景名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_scene_config', + 'COLUMN', N'scene_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_scene_config', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组状态 0、未启用 1、启用', + 'SCHEMA', N'dbo', + 'TABLE', N'er_scene_config', + 'COLUMN', N'scene_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'最大重试次数', + 'SCHEMA', N'dbo', + 'TABLE', N'er_scene_config', + 'COLUMN', N'max_retry_count' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'1、默认等级 2、固定间隔时间 3、CRON 表达式', + 'SCHEMA', N'dbo', + 'TABLE', N'er_scene_config', + 'COLUMN', N'back_off' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'间隔时长', + 'SCHEMA', N'dbo', + 'TABLE', N'er_scene_config', + 'COLUMN', N'trigger_interval' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'Deadline Request 调用链超时 单位毫秒', + 'SCHEMA', N'dbo', + 'TABLE', N'er_scene_config', + 'COLUMN', N'deadline_request' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务执行超时时间,单位秒', + 'SCHEMA', N'dbo', + 'TABLE', N'er_scene_config', + 'COLUMN', N'executor_timeout' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'路由策略', + 'SCHEMA', N'dbo', + 'TABLE', N'er_scene_config', + 'COLUMN', N'route_key' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'描述', + 'SCHEMA', N'dbo', + 'TABLE', N'er_scene_config', + 'COLUMN', N'description' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_scene_config', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_scene_config', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'场景配置', + 'SCHEMA', N'dbo', + 'TABLE', N'er_scene_config' +GO + +-- er_sequence_alloc +CREATE TABLE er_sequence_alloc +( + id bigint PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL DEFAULT '', + max_id bigint NOT NULL DEFAULT '1', + step int NOT NULL DEFAULT '100', + update_dt datetime2 NOT NULL DEFAULT GETDATE() +) +GO + +CREATE UNIQUE NONCLUSTERED INDEX uk_namespace_id_group_name ON er_sequence_alloc (namespace_id ASC, group_name ASC) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'er_sequence_alloc', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_sequence_alloc', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_sequence_alloc', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'最大id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_sequence_alloc', + 'COLUMN', N'max_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'步长', + 'SCHEMA', N'dbo', + 'TABLE', N'er_sequence_alloc', + 'COLUMN', N'step' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_sequence_alloc', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'号段模式序号ID分配表', + 'SCHEMA', N'dbo', + 'TABLE', N'er_sequence_alloc' +GO + +-- er_server_node +CREATE TABLE er_server_node +( + id bigint PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + host_id nvarchar(64) NOT NULL, + host_ip nvarchar(64) NOT NULL, + context_path nvarchar(256) NOT NULL DEFAULT '/', + host_port int NOT NULL, + expire_at datetime2 NOT NULL, + node_type tinyint NOT NULL, + ext_attrs nvarchar(256) NULL DEFAULT '', + create_dt datetime2 NOT NULL DEFAULT GETDATE(), + update_dt datetime2 NOT NULL DEFAULT GETDATE() +) +GO + +CREATE UNIQUE NONCLUSTERED INDEX uk_host_id_host_ip ON er_server_node (host_id ASC, host_ip ASC) +GO +CREATE NONCLUSTERED INDEX idx_namespace_id_group_name ON er_server_node (namespace_id ASC, group_name ASC) +GO +CREATE NONCLUSTERED INDEX idx_expire_at_node_type ON er_server_node (expire_at ASC, node_type ASC) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'er_server_node', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_server_node', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_server_node', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主机id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_server_node', + 'COLUMN', N'host_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'机器ip', + 'SCHEMA', N'dbo', + 'TABLE', N'er_server_node', + 'COLUMN', N'host_ip' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'客户端上下文路径 server.servlet.context-path', + 'SCHEMA', N'dbo', + 'TABLE', N'er_server_node', + 'COLUMN', N'context_path' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'机器端口', + 'SCHEMA', N'dbo', + 'TABLE', N'er_server_node', + 'COLUMN', N'host_port' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'过期时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_server_node', + 'COLUMN', N'expire_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'节点类型 1、客户端 2、是服务端', + 'SCHEMA', N'dbo', + 'TABLE', N'er_server_node', + 'COLUMN', N'node_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'er_server_node', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_server_node', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_server_node', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'服务器节点', + 'SCHEMA', N'dbo', + 'TABLE', N'er_server_node' +GO + +-- er_system_user +CREATE TABLE er_system_user +( + id bigint PRIMARY KEY IDENTITY, + username nvarchar(64) NOT NULL, + password nvarchar(128) NOT NULL, + role tinyint NOT NULL DEFAULT '0', + create_dt datetime2 NOT NULL DEFAULT GETDATE(), + update_dt datetime2 NOT NULL DEFAULT GETDATE() +) +GO + +CREATE UNIQUE NONCLUSTERED INDEX uk_username ON er_system_user (username ASC) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'er_system_user', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'账号', + 'SCHEMA', N'dbo', + 'TABLE', N'er_system_user', + 'COLUMN', N'username' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'密码', + 'SCHEMA', N'dbo', + 'TABLE', N'er_system_user', + 'COLUMN', N'password' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'角色:1-普通用户、2-管理员', + 'SCHEMA', N'dbo', + 'TABLE', N'er_system_user', + 'COLUMN', N'role' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_system_user', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_system_user', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'系统用户表', + 'SCHEMA', N'dbo', + 'TABLE', N'er_system_user' +GO + +-- pwd: admin +INSERT INTO er_system_user(username, password, role, create_dt, update_dt) VALUES (N'admin', N'465c194afb65670f38322df087f0a9bb225cc257e43eb4ac5a0c98ef5b3173ac', N'2', getdate(), getdate()); +GO + +-- er_system_user_permission +CREATE TABLE er_system_user_permission +( + id bigint PRIMARY KEY IDENTITY, + group_name nvarchar(64) NOT NULL, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + system_user_id bigint NOT NULL, + create_dt datetime2 NOT NULL DEFAULT GETDATE(), + update_dt datetime2 NOT NULL DEFAULT GETDATE() +) +GO + +CREATE UNIQUE NONCLUSTERED INDEX uk_namespace_id_group_name_system_user_id ON er_system_user_permission (namespace_id ASC, group_name ASC, system_user_id ASC) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'er_system_user_permission', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_system_user_permission', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_system_user_permission', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'系统用户id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_system_user_permission', + 'COLUMN', N'system_user_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_system_user_permission', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_system_user_permission', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'系统用户权限表', + 'SCHEMA', N'dbo', + 'TABLE', N'er_system_user_permission' +GO + + +-- er_workflow +CREATE TABLE er_workflow +( + id bigint IDENTITY, + workflow_name nvarchar(64) NOT NULL, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + workflow_status tinyint NOT NULL DEFAULT '1', + trigger_type tinyint NOT NULL, + trigger_interval nvarchar(255) NOT NULL, + next_trigger_at bigint NOT NULL, + block_strategy tinyint NOT NULL DEFAULT '1', + executor_timeout int NOT NULL DEFAULT '0', + description nvarchar(256) NOT NULL DEFAULT '', + flow_info nvarchar(max) NULL DEFAULT NULL, + bucket_index int NOT NULL DEFAULT '0', + version int NOT NULL, + create_dt datetime2 NOT NULL DEFAULT GETDATE(), + update_dt datetime2 NOT NULL DEFAULT GETDATE(), + deleted BIT DEFAULT 0, + ext_attrs nvarchar(256) NULL +) +GO + +CREATE NONCLUSTERED INDEX idx_create_dt ON er_workflow (create_dt ASC) +GO +CREATE NONCLUSTERED INDEX idx_namespace_id_group_name ON er_workflow (namespace_id ASC, group_name ASC) +GO + + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow', + 'COLUMN', N'workflow_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流状态 0、关闭、1、开启', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow', + 'COLUMN', N'workflow_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'触发类型 1.CRON 表达式 2. 固定时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow', + 'COLUMN', N'trigger_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'间隔时长', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow', + 'COLUMN', N'trigger_interval' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'下次触发时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow', + 'COLUMN', N'next_trigger_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'阻塞策略 1、丢弃 2、覆盖 3、并行', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow', + 'COLUMN', N'block_strategy' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务执行超时时间,单位秒', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow', + 'COLUMN', N'executor_timeout' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'描述', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow', + 'COLUMN', N'description' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'流程信息', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow', + 'COLUMN', N'flow_info' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'bucket', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow', + 'COLUMN', N'bucket_index' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'版本号', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow', + 'COLUMN', N'version' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'逻辑删除 1、删除', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow' +GO + +-- er_workflow_node +CREATE TABLE er_workflow_node +( + id bigint PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + node_name nvarchar(64) NOT NULL, + group_name nvarchar(64) NOT NULL, + job_id bigint NOT NULL, + workflow_id bigint NOT NULL, + node_type tinyint NOT NULL DEFAULT '1', + expression_type tinyint NOT NULL DEFAULT '0', + fail_strategy tinyint NOT NULL DEFAULT '1', + workflow_node_status tinyint NOT NULL DEFAULT '1', + priority_level int NOT NULL DEFAULT '1', + node_info nvarchar(max) NULL DEFAULT NULL, + version int NOT NULL, + create_dt datetime2 NOT NULL DEFAULT GETDATE(), + update_dt datetime2 NOT NULL DEFAULT GETDATE(), + deleted BIT DEFAULT 0, + ext_attrs nvarchar(256) NULL DEFAULT '' +) +GO + +CREATE NONCLUSTERED INDEX idx_create_dt ON er_workflow_node (create_dt ASC) +GO +CREATE NONCLUSTERED INDEX idx_namespace_id_group_name ON er_workflow_node (namespace_id ASC, group_name ASC) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow_node', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow_node', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'节点名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow_node', + 'COLUMN', N'node_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow_node', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务信息id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow_node', + 'COLUMN', N'job_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流ID', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow_node', + 'COLUMN', N'workflow_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'1、任务节点 2、条件节点', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow_node', + 'COLUMN', N'node_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'1、SpEl、2、Aviator 3、QL', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow_node', + 'COLUMN', N'expression_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'失败策略 1、跳过 2、阻塞', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow_node', + 'COLUMN', N'fail_strategy' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流节点状态 0、关闭、1、开启', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow_node', + 'COLUMN', N'workflow_node_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'优先级', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow_node', + 'COLUMN', N'priority_level' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'节点信息 ', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow_node', + 'COLUMN', N'node_info' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'版本号', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow_node', + 'COLUMN', N'version' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow_node', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow_node', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'逻辑删除 1、删除', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow_node', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow_node', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流节点', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow_node' +GO + +-- er_workflow_task_batch +CREATE TABLE er_workflow_task_batch +( + id bigint PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + workflow_id bigint NOT NULL, + task_batch_status tinyint NOT NULL DEFAULT '0', + operation_reason tinyint NOT NULL DEFAULT '0', + flow_info nvarchar(max) NULL DEFAULT NULL, + execution_at bigint NOT NULL DEFAULT '0', + create_dt datetime2 NOT NULL DEFAULT GETDATE(), + update_dt datetime2 NOT NULL DEFAULT GETDATE(), + deleted BIT DEFAULT 0, + ext_attrs nvarchar(256) NULL DEFAULT '' +) +GO + +CREATE NONCLUSTERED INDEX idx_job_id_task_batch_status ON er_workflow_task_batch (workflow_id ASC, task_batch_status ASC) +GO +CREATE NONCLUSTERED INDEX idx_create_dt ON er_workflow_task_batch (create_dt ASC) +GO +CREATE NONCLUSTERED INDEX idx_namespace_id_group_name ON er_workflow_task_batch (namespace_id ASC, group_name ASC) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow_task_batch', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow_task_batch', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow_task_batch', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流任务id', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow_task_batch', + 'COLUMN', N'workflow_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务批次状态 0、失败 1、成功', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow_task_batch', + 'COLUMN', N'task_batch_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'操作原因', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow_task_batch', + 'COLUMN', N'operation_reason' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'流程信息', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow_task_batch', + 'COLUMN', N'flow_info' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务执行时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow_task_batch', + 'COLUMN', N'execution_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow_task_batch', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow_task_batch', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'逻辑删除 1、删除', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow_task_batch', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow_task_batch', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流批次', + 'SCHEMA', N'dbo', + 'TABLE', N'er_workflow_task_batch' +GO diff --git a/script/sql/sqlserver/flowable.sql b/script/sql/sqlserver/flowable.sql new file mode 100644 index 000000000..1b09fc9cd --- /dev/null +++ b/script/sql/sqlserver/flowable.sql @@ -0,0 +1,447 @@ +insert into sys_menu values('11616', '工作流' , '0', '6', 'workflow', '', '', '1', '0', 'M', '0', '0', '', 'tree-table', 103, 1, getdate(), NULL, NULL, ''); +insert into sys_menu values('11617', '模型管理', '11616', '2', 'model', 'workflow/model/index', '', '1', '1', 'C', '0', '0', 'workflow:model:list', 'tree-table', 103, 1, getdate(), NULL, NULL, ''); +insert into sys_menu values('11618', '我的任务', '0', '7', 'task', '', '', '1', '0', 'M', '0', '0', '', 'tree-table', 103, 1, getdate(), NULL, NULL, ''); +insert into sys_menu values('11619', '我的待办', '11618', '2', 'taskWaiting', 'workflow/task/taskWaiting', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, getdate(), NULL, NULL, ''); +insert into sys_menu values('11632', '我的已办', '11618', '3', 'taskFinish', 'workflow/task/taskFinish', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, getdate(), NULL, NULL, ''); +insert into sys_menu values('11633', '我的抄送', '11618', '4', 'taskCopyList', 'workflow/task/taskCopyList', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, getdate(), NULL, NULL, ''); +insert into sys_menu values('11620', '流程定义', '11616', '3', 'processDefinition', 'workflow/processDefinition/index', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, getdate(), NULL, NULL, ''); +insert into sys_menu values('11621', '流程实例', '11630', '1', 'processInstance', 'workflow/processInstance/index', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, getdate(), NULL, NULL, ''); +insert into sys_menu values('11622', '流程分类', '11616', '1', 'category', 'workflow/category/index', '', '1', '0', 'C', '0', '0', 'workflow:category:list', 'tree-table', 103, 1, getdate(), NULL, NULL, ''); +insert into sys_menu values('11629', '我发起的', '11618', '1', 'myDocument', 'workflow/task/myDocument', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, getdate(), NULL, NULL, ''); +insert into sys_menu values('11630', '流程监控', '11616', '4', 'monitor', '', '', '1', '0', 'M', '0', '0', '', 'tree-table', 103, 1, getdate(), NULL, NULL, ''); +insert into sys_menu values('11631', '待办任务', '11630', '2', 'allTaskWaiting', 'workflow/task/allTaskWaiting', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, getdate(), NULL, NULL, ''); + + +-- 流程分类管理相关按钮 +insert into sys_menu values ('11623', '流程分类查询', '11622', '1', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:query', '#', 103, 1, getdate(), null, null, ''); +insert into sys_menu values ('11624', '流程分类新增', '11622', '2', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:add', '#', 103, 1, getdate(), null, null, ''); +insert into sys_menu values ('11625', '流程分类修改', '11622', '3', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:edit', '#', 103, 1, getdate(), null, null, ''); +insert into sys_menu values ('11626', '流程分类删除', '11622', '4', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:remove','#', 103, 1, getdate(), null, null, ''); +insert into sys_menu values ('11627', '流程分类导出', '11622', '5', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:export','#', 103, 1, getdate(), null, null, ''); +-- 请假单信息 +create table test_leave +( + id bigint not null + primary key, + leave_type nvarchar(255) not null, + start_date datetime2 not null, + end_date datetime2 not null, + leave_days int not null, + remark nvarchar(255), + create_dept bigint, + create_by bigint, + create_time datetime2, + update_by bigint, + update_time datetime2, + tenant_id nvarchar(20) +) +go + +exec sp_addextendedproperty 'MS_Description', N'请假申请表', 'SCHEMA', 'dbo', 'TABLE', 'test_leave' +go + +exec sp_addextendedproperty 'MS_Description', N'主键', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN', 'id' +go + +exec sp_addextendedproperty 'MS_Description', N'请假类型', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN', + 'leave_type' +go + +exec sp_addextendedproperty 'MS_Description', N'开始时间', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN', + 'start_date' +go + +exec sp_addextendedproperty 'MS_Description', N'结束时间', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN', 'end_date' +go + +exec sp_addextendedproperty 'MS_Description', N'请假天数', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN', + 'leave_days' +go + +exec sp_addextendedproperty 'MS_Description', N'请假原因', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN', 'remark' +go + +exec sp_addextendedproperty 'MS_Description', N'创建部门', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN', + 'create_dept' +go + +exec sp_addextendedproperty 'MS_Description', N'创建者', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN', 'create_by' +go + +exec sp_addextendedproperty 'MS_Description', N'创建时间', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN', + 'create_time' +go + +exec sp_addextendedproperty 'MS_Description', N'更新者', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN', 'update_by' +go + +exec sp_addextendedproperty 'MS_Description', N'更新时间', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN', + 'update_time' +go + +exec sp_addextendedproperty 'MS_Description', N'租户编号', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN', 'tenant_id' +go + +-- 流程分类信息表 +create table wf_category +( + id bigint not null + primary key, + category_name nvarchar(255), + category_code nvarchar(255) + constraint uni_category_code + unique, + parent_id bigint, + sort_num int, + tenant_id nvarchar(20), + create_dept bigint, + create_by bigint, + create_time datetime2, + update_by bigint, + update_time datetime2 +) +go + +exec sp_addextendedproperty 'MS_Description', N'流程分类', 'SCHEMA', 'dbo', 'TABLE', 'wf_category' +go + +exec sp_addextendedproperty 'MS_Description', N'主键', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN', 'id' +go + +exec sp_addextendedproperty 'MS_Description', N'分类名称', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN', + 'category_name' +go + +exec sp_addextendedproperty 'MS_Description', N'分类编码', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN', + 'category_code' +go + +exec sp_addextendedproperty 'MS_Description', N'父级id', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN', 'parent_id' +go + +exec sp_addextendedproperty 'MS_Description', N'排序', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN', 'sort_num' +go + +exec sp_addextendedproperty 'MS_Description', N'租户编号', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN', + 'tenant_id' +go + +exec sp_addextendedproperty 'MS_Description', N'创建部门', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN', + 'create_dept' +go + +exec sp_addextendedproperty 'MS_Description', N'创建者', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN', 'create_by' +go + +exec sp_addextendedproperty 'MS_Description', N'创建时间', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN', + 'create_time' +go + +exec sp_addextendedproperty 'MS_Description', N'更新者', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN', 'update_by' +go + +exec sp_addextendedproperty 'MS_Description', N'更新时间', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN', + 'update_time' +go + +INSERT INTO wf_category values (1, 'OA', 'OA', 0, 0, '000000', 103, 1, getdate(), 1, getdate()); + +create table wf_task_back_node +( + id bigint not null primary key, + node_id nvarchar(255) not null, + node_name nvarchar(255) not null, + order_no int not null, + instance_id nvarchar(255) not null, + task_type nvarchar(255) not null, + assignee nvarchar(2000) not null, + tenant_id nvarchar(20), + create_dept bigint, + create_by bigint, + create_time datetime2, + update_by bigint, + update_time datetime2 +) + +go +exec sp_addextendedproperty 'MS_Description', N'节点审批记录', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node' +go + +exec sp_addextendedproperty 'MS_Description', N'主键', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN', 'id' +go + +exec sp_addextendedproperty 'MS_Description', N'节点id', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN', + 'node_id' +go + +exec sp_addextendedproperty 'MS_Description', N'节点名称', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN', + 'node_name' +go + +exec sp_addextendedproperty 'MS_Description', N'排序', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN', 'order_no' +go + +exec sp_addextendedproperty 'MS_Description', N'流程实例id', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN', 'instance_id' +go + +exec sp_addextendedproperty 'MS_Description', N'节点类型', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN', 'task_type' +go + +exec sp_addextendedproperty 'MS_Description', N'审批人', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN', 'assignee' +go + +exec sp_addextendedproperty 'MS_Description', N'租户编号', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN', + 'tenant_id' +go + +exec sp_addextendedproperty 'MS_Description', N'创建部门', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN', + 'create_dept' +go + +exec sp_addextendedproperty 'MS_Description', N'创建者', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN', 'create_by' +go + +exec sp_addextendedproperty 'MS_Description', N'创建时间', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN', + 'create_time' +go + +exec sp_addextendedproperty 'MS_Description', N'更新者', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN', 'update_by' +go + +exec sp_addextendedproperty 'MS_Description', N'更新时间', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN', + 'update_time' +go + +create table wf_definition_config +( + id bigint not null primary key, + table_name nvarchar(255) not null, + definition_id nvarchar(255) not null + constraint uni_definition_id + unique, + process_key nvarchar(255) not null, + version bigint not null, + tenant_id nvarchar(20), + create_dept bigint, + create_by bigint, + create_time datetime2, + update_by bigint, + update_time datetime2 +) + +go +exec sp_addextendedproperty 'MS_Description', N'流程定义配置', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config' +go + +exec sp_addextendedproperty 'MS_Description', N'主键', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN', 'id' +go + +exec sp_addextendedproperty 'MS_Description', N'表名', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN', + 'table_name' +go + +exec sp_addextendedproperty 'MS_Description', N'流程定义ID', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN', + 'definition_id' +go + +exec sp_addextendedproperty 'MS_Description', N'流程KEY', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN', + 'process_key' +go + +exec sp_addextendedproperty 'MS_Description', N'流程版本', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN', + 'version' +go + +exec sp_addextendedproperty 'MS_Description', N'租户编号', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN', + 'tenant_id' +go + +exec sp_addextendedproperty 'MS_Description', N'创建部门', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN', + 'create_dept' +go + +exec sp_addextendedproperty 'MS_Description', N'创建者', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN', 'create_by' +go + +exec sp_addextendedproperty 'MS_Description', N'创建时间', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN', + 'create_time' +go + +exec sp_addextendedproperty 'MS_Description', N'更新者', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN', 'update_by' +go + +exec sp_addextendedproperty 'MS_Description', N'更新时间', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN', + 'update_time' +go + +create table wf_form_manage +( + id bigint not null primary key, + form_name nvarchar(255) not null, + form_type nvarchar(255) not null, + router nvarchar(255) not null, + remark nvarchar(500) null, + tenant_id nvarchar(20), + create_dept bigint, + create_by bigint, + create_time datetime2, + update_by bigint, + update_time datetime2 +) + +go +exec sp_addextendedproperty 'MS_Description', N'表单管理', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage' +go + +exec sp_addextendedproperty 'MS_Description', N'主键', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN', 'id' +go + +exec sp_addextendedproperty 'MS_Description', N'表单名称', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN', + 'form_name' +go + +exec sp_addextendedproperty 'MS_Description', N'表单类型', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN', + 'form_type' +go + +exec sp_addextendedproperty 'MS_Description', N'路由地址/表单ID', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN', + 'router' +go + +exec sp_addextendedproperty 'MS_Description', N'备注', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN', + 'remark' +go + +exec sp_addextendedproperty 'MS_Description', N'租户编号', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN', + 'tenant_id' +go + +exec sp_addextendedproperty 'MS_Description', N'创建部门', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN', + 'create_dept' +go + +exec sp_addextendedproperty 'MS_Description', N'创建者', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN', 'create_by' +go + +exec sp_addextendedproperty 'MS_Description', N'创建时间', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN', + 'create_time' +go + +exec sp_addextendedproperty 'MS_Description', N'更新者', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN', 'update_by' +go + +exec sp_addextendedproperty 'MS_Description', N'更新时间', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN', + 'update_time' +go + +insert into wf_form_manage(id, form_name, form_type, router, remark, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1, '请假申请', 'static', '/demo/leaveEdit/index', NULL, '000000', 103, 1, getdate(), 1, getdate()); + +create table wf_node_config +( + id bigint not null primary key, + form_id bigint, + form_type nvarchar(255) , + node_name nvarchar(255) not null, + node_id nvarchar(255) not null, + definition_id nvarchar(255) not null, + apply_user_task nchar default ('0') null, + tenant_id nvarchar(20), + create_dept bigint, + create_by bigint, + create_time datetime2, + update_by bigint, + update_time datetime2 +) + +go +exec sp_addextendedproperty 'MS_Description', N'节点配置', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config' +go + +exec sp_addextendedproperty 'MS_Description', N'主键', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN', 'id' +go + +exec sp_addextendedproperty 'MS_Description', N'表单id', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN', + 'form_id' +go + +exec sp_addextendedproperty 'MS_Description', N'表单类型', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN', + 'form_type' +go + +exec sp_addextendedproperty 'MS_Description', N'节点名称', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN', + 'node_name' +go + +exec sp_addextendedproperty 'MS_Description', N'节点id', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN', + 'node_id' +go + +exec sp_addextendedproperty 'MS_Description', N'流程定义id', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN', + 'definition_id' +go + +exec sp_addextendedproperty 'MS_Description', N'是否为申请人节点 (0是 1否)', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN', + 'apply_user_task' +go + +exec sp_addextendedproperty 'MS_Description', N'租户编号', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN', + 'tenant_id' +go + +exec sp_addextendedproperty 'MS_Description', N'创建部门', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN', + 'create_dept' +go + +exec sp_addextendedproperty 'MS_Description', N'创建者', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN', 'create_by' +go + +exec sp_addextendedproperty 'MS_Description', N'创建时间', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN', + 'create_time' +go + +exec sp_addextendedproperty 'MS_Description', N'更新者', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN', 'update_by' +go + +exec sp_addextendedproperty 'MS_Description', N'更新时间', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN', + 'update_time' +go + +INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11638, '请假申请', 5, 1, 'leave', 'workflow/leave/index', 1, 0, 'C', '0', '0', 'demo:leave:list', '#', 103, 1, getdate(), NULL, NULL, '请假申请菜单'); +INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11639, '请假申请查询', 11638, 1, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:query', '#', 103, 1, getdate(), NULL, NULL, ''); +INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11640, '请假申请新增', 11638, 2, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:add', '#', 103, 1, getdate(), NULL, NULL, ''); +INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11641, '请假申请修改', 11638, 3, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:edit', '#', 103, 1, getdate(), NULL, NULL, ''); +INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11642, '请假申请删除', 11638, 4, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:remove', '#', 103, 1, getdate(), NULL, NULL, ''); +INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11643, '请假申请导出', 11638, 5, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:export', '#', 103, 1, getdate(), NULL, NULL, ''); + +INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (13, '000000', '业务状态', 'wf_business_status', 103, 1, getdate(), NULL, NULL, '业务状态列表'); +INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (14, '000000', '表单类型', 'wf_form_type', 103, 1, getdate(), NULL, NULL, '表单类型列表'); + +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (39, '000000', 1, '已撤销', 'cancel', 'wf_business_status', '', 'danger', 'N', 103, 1, getdate(), NULL, NULL, '已撤销'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (40, '000000', 2, '草稿', 'draft', 'wf_business_status', '', 'info', 'N', 103, 1, getdate(), NULL, NULL, '草稿'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (41, '000000', 3, '待审核', 'waiting', 'wf_business_status', '', 'primary', 'N', 103, 1,getdate(), NULL, NULL, '待审核'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (42, '000000', 4, '已完成', 'finish', 'wf_business_status', '', 'success', 'N', 103, 1, getdate(), NULL, NULL, '已完成'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (43, '000000', 5, '已作废', 'invalid', 'wf_business_status', '', 'danger', 'N', 103, 1, getdate(), NULL, NULL, '已作废'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (44, '000000', 6, '已退回', 'back', 'wf_business_status', '', 'danger', 'N', 103, 1, getdate(), NULL, NULL, '已退回'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (45, '000000', 7, '已终止', 'termination', 'wf_business_status', '', 'danger', 'N', 103, 1,getdate(), NULL, NULL, '已终止'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (46, '000000', 1, '自定义表单', 'static', 'wf_form_type', '', 'success', 'N', 103, 1, getdate(), NULL, NULL, '自定义表单'); +INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (47, '000000', 2, '动态表单', 'dynamic', 'wf_form_type', '', 'primary', 'N', 103, 1, getdate(), NULL, NULL, '动态表单'); + +-- 表单管理 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(11628, '表单管理', '11616', '5', 'formManage', 'workflow/formManage/index', 1, 0, 'C', '0', '0', 'workflow:formManage:list', 'tree-table', 103, 1, getdate(), null, null, '表单管理菜单'); + +-- 表单管理按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(11644, '表单管理查询', 11628, '1', '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:query', '', 103, 1, getdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(11645, '表单管理新增', 11628, '2', '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:add', '', 103, 1, getdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(11646, '表单管理修改', 11628, '3', '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:edit', '', 103, 1, getdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(11647, '表单管理删除', 11628, '4', '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:remove', '', 103, 1, getdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(11648, '表单管理导出', 11628, '5', '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:export', 'tree-table', 103, 1, getdate(), null, null, ''); diff --git a/script/sql/sqlserver/sqlserver_ry_vue_5.X.sql b/script/sql/sqlserver/sqlserver_ry_vue_5.X.sql index a27ac5def..9f1773100 100644 --- a/script/sql/sqlserver/sqlserver_ry_vue_5.X.sql +++ b/script/sql/sqlserver/sqlserver_ry_vue_5.X.sql @@ -17,7 +17,7 @@ create table sys_social union_id nvarchar(255) NULL, scope nvarchar(255) NULL, token_type nvarchar(255) NULL, - id_token nvarchar(255) NULL, + id_token nvarchar(2000) NULL, mac_algorithm nvarchar(255) NULL, mac_key nvarchar(255) NULL, code nvarchar(255) NULL, @@ -1647,6 +1647,8 @@ INSERT sys_menu VALUES (3, N'系统工具', 0, 4, N'tool', NULL, N'', 1, 0, N'M' GO INSERT sys_menu VALUES (4, N'PLUS官网', 0, 5, N'https://gitee.com/dromara/RuoYi-Vue-Plus', null, N'', 0, 0, N'M', N'0', N'0', N'', N'guide', 103, 1, getdate(), null, null, N'RuoYi-Vue-Plus官网地址'); GO +INSERT sys_menu VALUES (5, N'测试菜单', 0, 5, N'demo', NULL, N'', 1, 0, N'M', N'0', N'0', NULL, N'star', 103, 1, getdate(), NULL, NULL, N''); +GO INSERT sys_menu VALUES (100, N'用户管理', 1, 1, N'user', N'system/user/index', N'', 1, 0, N'C', N'0', N'0', N'system:user:list', N'user', 103, 1, getdate(), NULL, NULL, N'用户管理菜单') GO INSERT sys_menu VALUES (101, N'角色管理', 1, 2, N'role', N'system/role/index', N'', 1, 0, N'C', N'0', N'0', N'system:role:list', N'peoples', 103, 1, getdate(), NULL, NULL, N'角色管理菜单') @@ -1849,6 +1851,32 @@ INSERT sys_menu VALUES (1064, N'客户端管理删除', 123, 4, N'#', N'', N'', GO INSERT sys_menu VALUES (1065, N'客户端管理导出', 123, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:client:export', N'#', 103, 1, getdate(), NULL, NULL, N''); GO +-- 测试菜单 +INSERT sys_menu VALUES (1500, N'测试单表', 5, 1, N'demo', N'demo/demo/index', N'', 1, 0, N'C', N'0', N'0', N'demo:demo:list', N'#', 103, 1, getdate(), NULL, NULL, N'测试单表菜单'); +GO +INSERT sys_menu VALUES (1501, N'测试单表查询', 1500, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:demo:query', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1502, N'测试单表新增', 1500, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:demo:add', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1503, N'测试单表修改', 1500, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:demo:edit', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1504, N'测试单表删除', 1500, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:demo:remove', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1505, N'测试单表导出', 1500, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:demo:export', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO + +INSERT sys_menu VALUES (1506, N'测试树表', 5, 1, N'tree', N'demo/tree/index', N'', 1, 0, N'C', N'0', N'0', N'demo:tree:list', N'#', 103, 1, getdate(), NULL, NULL, N'测试树表菜单'); +GO +INSERT sys_menu VALUES (1507, N'测试树表查询', 1506, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:tree:query', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1508, N'测试树表新增', 1506, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:tree:add', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1509, N'测试树表修改', 1506, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:tree:edit', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1510, N'测试树表删除', 1506, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:tree:remove', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1511, N'测试树表导出', 1506, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:tree:export', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO CREATE TABLE sys_notice ( @@ -2340,7 +2368,9 @@ GO INSERT sys_role VALUES (1, N'000000', N'超级管理员', N'superadmin', 1, N'1', 1, 1, N'0', N'0', 103, 1, getdate(), NULL, NULL, N'超级管理员') GO -INSERT sys_role VALUES (2, N'000000', N'普通角色', N'common', 2, N'2', 1, 1, N'0', N'0', 103, 1, getdate(), NULL, NULL, N'普通角色') +INSERT sys_role VALUES (3, N'000000', N'本部门及以下', N'test1', 3, N'4', 1, 1, N'0', N'0', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_role VALUES (4, N'000000', N'仅本人', N'test2', 4, N'5', 1, 1, N'0', N'0', 103, 1, getdate(), NULL, NULL, N''); GO CREATE TABLE sys_role_dept @@ -2372,13 +2402,6 @@ EXEC sys.sp_addextendedproperty 'TABLE', N'sys_role_dept' GO -INSERT sys_role_dept VALUES (2, 100) -GO -INSERT sys_role_dept VALUES (2, 101) -GO -INSERT sys_role_dept VALUES (2, 105) -GO - CREATE TABLE sys_role_menu ( role_id bigint NOT NULL, @@ -2408,179 +2431,174 @@ EXEC sys.sp_addextendedproperty 'TABLE', N'sys_role_menu' GO -INSERT sys_role_menu VALUES (2, 1) +-- ---------------------------- +-- 初始化-角色和菜单关联表数据 +-- ---------------------------- +INSERT sys_role_menu VALUES (3, 1); GO -INSERT sys_role_menu VALUES (2, 2) +INSERT sys_role_menu VALUES (3, 5); GO -INSERT sys_role_menu VALUES (2, 3) +INSERT sys_role_menu VALUES (3, 100); GO -INSERT sys_role_menu VALUES (2, 100) +INSERT sys_role_menu VALUES (3, 101); GO -INSERT sys_role_menu VALUES (2, 101) +INSERT sys_role_menu VALUES (3, 102); GO -INSERT sys_role_menu VALUES (2, 102) +INSERT sys_role_menu VALUES (3, 103); GO -INSERT sys_role_menu VALUES (2, 103) +INSERT sys_role_menu VALUES (3, 104); GO -INSERT sys_role_menu VALUES (2, 104) +INSERT sys_role_menu VALUES (3, 105); GO -INSERT sys_role_menu VALUES (2, 105) +INSERT sys_role_menu VALUES (3, 106); GO -INSERT sys_role_menu VALUES (2, 106) +INSERT sys_role_menu VALUES (3, 107); GO -INSERT sys_role_menu VALUES (2, 107) +INSERT sys_role_menu VALUES (3, 108); GO -INSERT sys_role_menu VALUES (2, 108) +INSERT sys_role_menu VALUES (3, 500); GO -INSERT sys_role_menu VALUES (2, 109) +INSERT sys_role_menu VALUES (3, 501); GO -INSERT sys_role_menu VALUES (2, 110) +INSERT sys_role_menu VALUES (3, 1001); GO -INSERT sys_role_menu VALUES (2, 111) +INSERT sys_role_menu VALUES (3, 1002); GO -INSERT sys_role_menu VALUES (2, 112) +INSERT sys_role_menu VALUES (3, 1003); GO -INSERT sys_role_menu VALUES (2, 113) +INSERT sys_role_menu VALUES (3, 1004); GO -INSERT sys_role_menu VALUES (2, 114) +INSERT sys_role_menu VALUES (3, 1005); GO -INSERT sys_role_menu VALUES (2, 115) +INSERT sys_role_menu VALUES (3, 1006); GO -INSERT sys_role_menu VALUES (2, 116) +INSERT sys_role_menu VALUES (3, 1007); GO -INSERT sys_role_menu VALUES (2, 500) +INSERT sys_role_menu VALUES (3, 1008); GO -INSERT sys_role_menu VALUES (2, 501) +INSERT sys_role_menu VALUES (3, 1009); GO -INSERT sys_role_menu VALUES (2, 1001) +INSERT sys_role_menu VALUES (3, 1010); GO -INSERT sys_role_menu VALUES (2, 1002) +INSERT sys_role_menu VALUES (3, 1011); GO -INSERT sys_role_menu VALUES (2, 1003) +INSERT sys_role_menu VALUES (3, 1012); GO -INSERT sys_role_menu VALUES (2, 1004) +INSERT sys_role_menu VALUES (3, 1013); GO -INSERT sys_role_menu VALUES (2, 1005) +INSERT sys_role_menu VALUES (3, 1014); GO -INSERT sys_role_menu VALUES (2, 1006) +INSERT sys_role_menu VALUES (3, 1015); GO -INSERT sys_role_menu VALUES (2, 1007) +INSERT sys_role_menu VALUES (3, 1016); GO -INSERT sys_role_menu VALUES (2, 1008) +INSERT sys_role_menu VALUES (3, 1017); GO -INSERT sys_role_menu VALUES (2, 1009) +INSERT sys_role_menu VALUES (3, 1018); GO -INSERT sys_role_menu VALUES (2, 1010) +INSERT sys_role_menu VALUES (3, 1019); GO -INSERT sys_role_menu VALUES (2, 1011) +INSERT sys_role_menu VALUES (3, 1020); GO -INSERT sys_role_menu VALUES (2, 1012) +INSERT sys_role_menu VALUES (3, 1021); GO -INSERT sys_role_menu VALUES (2, 1013) +INSERT sys_role_menu VALUES (3, 1022); GO -INSERT sys_role_menu VALUES (2, 1014) +INSERT sys_role_menu VALUES (3, 1023); GO -INSERT sys_role_menu VALUES (2, 1015) +INSERT sys_role_menu VALUES (3, 1024); GO -INSERT sys_role_menu VALUES (2, 1016) +INSERT sys_role_menu VALUES (3, 1025); GO -INSERT sys_role_menu VALUES (2, 1017) +INSERT sys_role_menu VALUES (3, 1026); GO -INSERT sys_role_menu VALUES (2, 1018) +INSERT sys_role_menu VALUES (3, 1027); GO -INSERT sys_role_menu VALUES (2, 1019) +INSERT sys_role_menu VALUES (3, 1028); GO -INSERT sys_role_menu VALUES (2, 1020) +INSERT sys_role_menu VALUES (3, 1029); GO -INSERT sys_role_menu VALUES (2, 1021) +INSERT sys_role_menu VALUES (3, 1030); GO -INSERT sys_role_menu VALUES (2, 1022) +INSERT sys_role_menu VALUES (3, 1031); GO -INSERT sys_role_menu VALUES (2, 1023) +INSERT sys_role_menu VALUES (3, 1032); GO -INSERT sys_role_menu VALUES (2, 1024) +INSERT sys_role_menu VALUES (3, 1033); GO -INSERT sys_role_menu VALUES (2, 1025) +INSERT sys_role_menu VALUES (3, 1034); GO -INSERT sys_role_menu VALUES (2, 1026) +INSERT sys_role_menu VALUES (3, 1035); GO -INSERT sys_role_menu VALUES (2, 1027) +INSERT sys_role_menu VALUES (3, 1036); GO -INSERT sys_role_menu VALUES (2, 1028) +INSERT sys_role_menu VALUES (3, 1037); GO -INSERT sys_role_menu VALUES (2, 1029) +INSERT sys_role_menu VALUES (3, 1038); GO -INSERT sys_role_menu VALUES (2, 1030) +INSERT sys_role_menu VALUES (3, 1039); GO -INSERT sys_role_menu VALUES (2, 1031) +INSERT sys_role_menu VALUES (3, 1040); GO -INSERT sys_role_menu VALUES (2, 1032) +INSERT sys_role_menu VALUES (3, 1041); GO -INSERT sys_role_menu VALUES (2, 1033) +INSERT sys_role_menu VALUES (3, 1042); GO -INSERT sys_role_menu VALUES (2, 1034) +INSERT sys_role_menu VALUES (3, 1043); GO -INSERT sys_role_menu VALUES (2, 1035) +INSERT sys_role_menu VALUES (3, 1044); GO -INSERT sys_role_menu VALUES (2, 1036) +INSERT sys_role_menu VALUES (3, 1045); GO -INSERT sys_role_menu VALUES (2, 1037) +INSERT sys_role_menu VALUES (3, 1500); GO -INSERT sys_role_menu VALUES (2, 1038) +INSERT sys_role_menu VALUES (3, 1501); GO -INSERT sys_role_menu VALUES (2, 1039) +INSERT sys_role_menu VALUES (3, 1502); GO -INSERT sys_role_menu VALUES (2, 1040) +INSERT sys_role_menu VALUES (3, 1503); GO -INSERT sys_role_menu VALUES (2, 1041) +INSERT sys_role_menu VALUES (3, 1504); GO -INSERT sys_role_menu VALUES (2, 1042) +INSERT sys_role_menu VALUES (3, 1505); GO -INSERT sys_role_menu VALUES (2, 1043) +INSERT sys_role_menu VALUES (3, 1506); GO -INSERT sys_role_menu VALUES (2, 1044) +INSERT sys_role_menu VALUES (3, 1507); GO -INSERT sys_role_menu VALUES (2, 1045) +INSERT sys_role_menu VALUES (3, 1508); GO -INSERT sys_role_menu VALUES (2, 1046) +INSERT sys_role_menu VALUES (3, 1509); GO -INSERT sys_role_menu VALUES (2, 1047) +INSERT sys_role_menu VALUES (3, 1510); GO -INSERT sys_role_menu VALUES (2, 1048) +INSERT sys_role_menu VALUES (3, 1511); GO -INSERT sys_role_menu VALUES (2, 1049) +INSERT sys_role_menu VALUES (4, 5); GO -INSERT sys_role_menu VALUES (2, 1050) +INSERT sys_role_menu VALUES (4, 1500); GO -INSERT sys_role_menu VALUES (2, 1051) +INSERT sys_role_menu VALUES (4, 1501); GO -INSERT sys_role_menu VALUES (2, 1052) +INSERT sys_role_menu VALUES (4, 1502); GO -INSERT sys_role_menu VALUES (2, 1053) +INSERT sys_role_menu VALUES (4, 1503); GO -INSERT sys_role_menu VALUES (2, 1054) +INSERT sys_role_menu VALUES (4, 1504); GO -INSERT sys_role_menu VALUES (2, 1055) +INSERT sys_role_menu VALUES (4, 1505); GO -INSERT sys_role_menu VALUES (2, 1056) +INSERT sys_role_menu VALUES (4, 1506); GO -INSERT sys_role_menu VALUES (2, 1057) +INSERT sys_role_menu VALUES (4, 1507); GO -INSERT sys_role_menu VALUES (2, 1058) +INSERT sys_role_menu VALUES (4, 1508); GO -INSERT sys_role_menu VALUES (2, 1059) +INSERT sys_role_menu VALUES (4, 1509); GO -INSERT sys_role_menu VALUES (2, 1060) +INSERT sys_role_menu VALUES (4, 1510); GO -INSERT sys_role_menu VALUES (2, 1061) -GO -INSERT sys_role_menu VALUES (2, 1062) -GO -INSERT sys_role_menu VALUES (2, 1063) -GO -INSERT sys_role_menu VALUES (2, 1064) -GO -INSERT sys_role_menu VALUES (2, 1065) +INSERT sys_role_menu VALUES (4, 1511); GO CREATE TABLE sys_user @@ -2747,7 +2765,9 @@ GO INSERT sys_user VALUES (1, N'000000', 103, N'admin', N'疯狂的狮子Li', N'sys_user', N'crazyLionLi@163.com', N'15888888888', N'1', NULL, N'$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', N'0', N'0', N'127.0.0.1', getdate(), 103, 1, getdate(), NULL, NULL, N'管理员') GO -INSERT sys_user VALUES (2, N'000000', 105, N'lionli', N'疯狂的狮子Li', N'sys_user', N'crazyLionLi@qq.com', N'15666666666', N'1', NULL, N'$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', N'0', N'0', N'127.0.0.1', getdate(), 103, 1, getdate(), NULL, NULL, N'测试员') +INSERT sys_user VALUES (3, N'000000', 108, N'test', N'本部门及以下 密码666666', N'sys_user', N'', N'', N'0', NULL, N'$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', N'0', N'0', N'127.0.0.1', getdate(), 103, 1, getdate(), 3, getdate(), NULL); +GO +INSERT sys_user VALUES (4, N'000000', 102, N'test1', N'仅本人 密码666666', N'sys_user', N'', N'', N'0', NULL, N'$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', N'0', N'0', N'127.0.0.1', getdate(), 103, 1, getdate(), 4, getdate(), NULL); GO CREATE TABLE sys_user_post @@ -2781,8 +2801,6 @@ GO INSERT sys_user_post VALUES (1, 1) GO -INSERT sys_user_post VALUES (2, 2) -GO CREATE TABLE sys_user_role ( @@ -2815,7 +2833,9 @@ GO INSERT sys_user_role VALUES (1, 1) GO -INSERT sys_user_role VALUES (2, 2) +INSERT sys_user_role VALUES (3, 3); +GO +INSERT sys_user_role VALUES (4, 4); GO CREATE TABLE sys_oss @@ -3109,102 +3129,402 @@ ON [PRIMARY] GO EXEC sp_addextendedproperty -'MS_Description', N'主建', -'SCHEMA', N'dbo', -'TABLE', N'sys_client', -'COLUMN', N'id' + 'MS_Description', N'主建', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'id' GO EXEC sys.sp_addextendedproperty -'MS_Description', N'客户端id' , -'SCHEMA', N'dbo', -'TABLE', N'sys_client', -'COLUMN', N'client_id' + 'MS_Description', N'客户端id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'client_id' GO EXEC sp_addextendedproperty -'MS_Description', N'客户端key', -'SCHEMA', N'dbo', -'TABLE', N'sys_client', -'COLUMN', N'client_key' + 'MS_Description', N'客户端key', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'client_key' GO EXEC sp_addextendedproperty -'MS_Description', N'客户端秘钥', -'SCHEMA', N'dbo', -'TABLE', N'sys_client', -'COLUMN', N'client_secret' + 'MS_Description', N'客户端秘钥', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'client_secret' GO EXEC sp_addextendedproperty -'MS_Description', N'授权类型', -'SCHEMA', N'dbo', -'TABLE', N'sys_client', -'COLUMN', N'grant_type' + 'MS_Description', N'授权类型', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'grant_type' GO EXEC sp_addextendedproperty -'MS_Description', N'设备类型', -'SCHEMA', N'dbo', -'TABLE', N'sys_client', -'COLUMN', N'device_type' + 'MS_Description', N'设备类型', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'device_type' GO EXEC sp_addextendedproperty -'MS_Description', N'token活跃超时时间', -'SCHEMA', N'dbo', -'TABLE', N'sys_client', -'COLUMN', N'active_timeout' + 'MS_Description', N'token活跃超时时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'active_timeout' GO EXEC sp_addextendedproperty -'MS_Description', N'token固定超时', -'SCHEMA', N'dbo', -'TABLE', N'sys_client', -'COLUMN', N'timeout' + 'MS_Description', N'token固定超时', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'timeout' GO EXEC sp_addextendedproperty -'MS_Description', N'状态(0正常 1停用)', -'SCHEMA', N'dbo', -'TABLE', N'sys_client', -'COLUMN', N'status' + 'MS_Description', N'状态(0正常 1停用)', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'status' GO EXEC sp_addextendedproperty -'MS_Description', N'删除标志(0代表存在 2代表删除)', -'SCHEMA', N'dbo', -'TABLE', N'sys_client', -'COLUMN', N'del_flag' + 'MS_Description', N'删除标志(0代表存在 2代表删除)', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'del_flag' GO EXEC sys.sp_addextendedproperty -'MS_Description', N'创建部门' , -'SCHEMA', N'dbo', -'TABLE', N'sys_client', -'COLUMN', N'create_dept' + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'create_dept' GO EXEC sp_addextendedproperty -'MS_Description', N'创建者', -'SCHEMA', N'dbo', -'TABLE', N'sys_client', -'COLUMN', N'create_by' + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'create_by' GO EXEC sp_addextendedproperty -'MS_Description', N'创建时间', -'SCHEMA', N'dbo', -'TABLE', N'sys_client', -'COLUMN', N'create_time' + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'create_time' GO EXEC sp_addextendedproperty -'MS_Description', N'更新者', -'SCHEMA', N'dbo', -'TABLE', N'sys_client', -'COLUMN', N'update_by' + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'update_by' GO EXEC sp_addextendedproperty -'MS_Description', N'更新时间', -'SCHEMA', N'dbo', -'TABLE', N'sys_client', -'COLUMN', N'update_time' + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'update_time' GO EXEC sp_addextendedproperty -'MS_Description', N'系统授权表', -'SCHEMA', N'dbo', -'TABLE', N'sys_client' + 'MS_Description', N'系统授权表', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client' GO INSERT INTO sys_client VALUES (N'1', N'e5cd7e4891bf95d1d19206ce24a7b32e', N'pc', N'pc123', N'password,social', N'pc', 1800, 604800, N'0', N'0', 103, 1, getdate(), 1, getdate()) GO INSERT INTO sys_client VALUES (N'2', N'428a8310cd442757ae699df5d894f051', N'app', N'app123', N'password,sms,social', N'android', 1800, 604800, N'0', N'0', 103, 1, getdate(), 1, getdate()) GO + +CREATE TABLE test_demo +( + id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT ('000000') NULL, + dept_id bigint NULL, + user_id bigint NULL, + order_num int DEFAULT ((0)) NULL, + test_key nvarchar(255) NULL, + value nvarchar(255) NULL, + version int DEFAULT ((0)) NULL, + create_dept bigint NULL, + create_time datetime2(0) NULL, + create_by bigint NULL, + update_time datetime2(0) NULL, + update_by bigint NULL, + del_flag int DEFAULT ((0)) NULL, + CONSTRAINT PK__test_dem__3213E83F176051C8 PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户id', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'部门id', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'dept_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户id', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'user_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'排序号', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'order_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'key键', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'test_key' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'值', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'value' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'版本', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'version' +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'create_dept' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建人', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'create_by' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新人', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'update_by' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'删除标志', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'测试单表', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo' +GO + +CREATE TABLE test_tree +( + id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT ('000000') NULL, + parent_id bigint DEFAULT ((0)) NULL, + dept_id bigint NULL, + user_id bigint NULL, + tree_name nvarchar(255) NULL, + version int DEFAULT ((0)) NULL, + create_dept bigint NULL, + create_time datetime2(0) NULL, + create_by bigint NULL, + update_time datetime2(0) NULL, + update_by bigint NULL, + del_flag int DEFAULT ((0)) NULL, + CONSTRAINT PK__test_tre__3213E83FC75A1B63 PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户id', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'父id', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'parent_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'部门id', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'dept_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户id', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'user_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'值', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'tree_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'版本', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'version' +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'create_dept' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建人', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'create_by' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新人', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'update_by' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'删除标志', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'测试树表', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree' +GO + +INSERT test_demo VALUES (1, N'000000', 102, 4, 1, N'测试数据权限', N'测试', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (2, N'000000', 102, 3, 2, N'子节点1', N'111', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (3, N'000000', 102, 3, 3, N'子节点2', N'222', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (4, N'000000', 108, 4, 4, N'测试数据', N'demo', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (5, N'000000', 108, 3, 13, N'子节点11', N'1111', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (6, N'000000', 108, 3, 12, N'子节点22', N'2222', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (7, N'000000', 108, 3, 11, N'子节点33', N'3333', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (8, N'000000', 108, 3, 10, N'子节点44', N'4444', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (9, N'000000', 108, 3, 9, N'子节点55', N'5555', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (10, N'000000', 108, 3, 8, N'子节点66', N'6666', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (11, N'000000', 108, 3, 7, N'子节点77', N'7777', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (12, N'000000', 108, 3, 6, N'子节点88', N'8888', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (13, N'000000', 108, 3, 5, N'子节点99', N'9999', 0, 103, getdate(), 1, NULL, NULL, 0); +GO + +INSERT test_tree VALUES (1, N'000000', 0, 102, 4, N'测试数据权限', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (2, N'000000', 1, 102, 3, N'子节点1', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (3, N'000000', 2, 102, 3, N'子节点2', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (4, N'000000', 0, 108, 4, N'测试树1', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (5, N'000000', 4, 108, 3, N'子节点11', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (6, N'000000', 4, 108, 3, N'子节点22', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (7, N'000000', 4, 108, 3, N'子节点33', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (8, N'000000', 5, 108, 3, N'子节点44', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (9, N'000000', 6, 108, 3, N'子节点55', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (10, N'000000', 7, 108, 3, N'子节点66', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (11, N'000000', 7, 108, 3, N'子节点77', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (12, N'000000', 10, 108, 3, N'子节点88', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (13, N'000000', 10, 108, 3, N'子节点99', 0, 103, getdate(), 1, NULL, NULL, 0); +GO diff --git a/script/sql/sqlserver/sqlserver_test.sql b/script/sql/sqlserver/sqlserver_test.sql deleted file mode 100644 index 87628bd66..000000000 --- a/script/sql/sqlserver/sqlserver_test.sql +++ /dev/null @@ -1,510 +0,0 @@ -CREATE TABLE test_demo -( - id bigint NOT NULL, - tenant_id nvarchar(20) DEFAULT ('000000') NULL, - dept_id bigint NULL, - user_id bigint NULL, - order_num int DEFAULT ((0)) NULL, - test_key nvarchar(255) NULL, - value nvarchar(255) NULL, - version int DEFAULT ((0)) NULL, - create_dept bigint NULL, - create_time datetime2(0) NULL, - create_by bigint NULL, - update_time datetime2(0) NULL, - update_by bigint NULL, - del_flag int DEFAULT ((0)) NULL, - CONSTRAINT PK__test_dem__3213E83F176051C8 PRIMARY KEY CLUSTERED (id) - WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) - ON [PRIMARY] -) -ON [PRIMARY] -GO - -EXEC sp_addextendedproperty - 'MS_Description', N'主键', - 'SCHEMA', N'dbo', - 'TABLE', N'test_demo', - 'COLUMN', N'id' -GO - -EXEC sp_addextendedproperty - 'MS_Description', N'租户id', - 'SCHEMA', N'dbo', - 'TABLE', N'test_demo', - 'COLUMN', N'tenant_id' -GO - -EXEC sp_addextendedproperty - 'MS_Description', N'部门id', - 'SCHEMA', N'dbo', - 'TABLE', N'test_demo', - 'COLUMN', N'dept_id' -GO - -EXEC sp_addextendedproperty - 'MS_Description', N'用户id', - 'SCHEMA', N'dbo', - 'TABLE', N'test_demo', - 'COLUMN', N'user_id' -GO - -EXEC sp_addextendedproperty - 'MS_Description', N'排序号', - 'SCHEMA', N'dbo', - 'TABLE', N'test_demo', - 'COLUMN', N'order_num' -GO - -EXEC sp_addextendedproperty - 'MS_Description', N'key键', - 'SCHEMA', N'dbo', - 'TABLE', N'test_demo', - 'COLUMN', N'test_key' -GO - -EXEC sp_addextendedproperty - 'MS_Description', N'值', - 'SCHEMA', N'dbo', - 'TABLE', N'test_demo', - 'COLUMN', N'value' -GO - -EXEC sp_addextendedproperty - 'MS_Description', N'版本', - 'SCHEMA', N'dbo', - 'TABLE', N'test_demo', - 'COLUMN', N'version' -GO - -EXEC sys.sp_addextendedproperty - 'MS_Description', N'创建部门' , - 'SCHEMA', N'dbo', - 'TABLE', N'test_demo', - 'COLUMN', N'create_dept' -GO - -EXEC sp_addextendedproperty - 'MS_Description', N'创建时间', - 'SCHEMA', N'dbo', - 'TABLE', N'test_demo', - 'COLUMN', N'create_time' -GO - -EXEC sp_addextendedproperty - 'MS_Description', N'创建人', - 'SCHEMA', N'dbo', - 'TABLE', N'test_demo', - 'COLUMN', N'create_by' -GO - -EXEC sp_addextendedproperty - 'MS_Description', N'更新时间', - 'SCHEMA', N'dbo', - 'TABLE', N'test_demo', - 'COLUMN', N'update_time' -GO - -EXEC sp_addextendedproperty - 'MS_Description', N'更新人', - 'SCHEMA', N'dbo', - 'TABLE', N'test_demo', - 'COLUMN', N'update_by' -GO - -EXEC sp_addextendedproperty - 'MS_Description', N'删除标志', - 'SCHEMA', N'dbo', - 'TABLE', N'test_demo', - 'COLUMN', N'del_flag' -GO - -EXEC sp_addextendedproperty - 'MS_Description', N'测试单表', - 'SCHEMA', N'dbo', - 'TABLE', N'test_demo' -GO - -CREATE TABLE test_tree -( - id bigint NOT NULL, - tenant_id nvarchar(20) DEFAULT ('000000') NULL, - parent_id bigint DEFAULT ((0)) NULL, - dept_id bigint NULL, - user_id bigint NULL, - tree_name nvarchar(255) NULL, - version int DEFAULT ((0)) NULL, - create_dept bigint NULL, - create_time datetime2(0) NULL, - create_by bigint NULL, - update_time datetime2(0) NULL, - update_by bigint NULL, - del_flag int DEFAULT ((0)) NULL, - CONSTRAINT PK__test_tre__3213E83FC75A1B63 PRIMARY KEY CLUSTERED (id) - WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) - ON [PRIMARY] -) -ON [PRIMARY] -GO - -EXEC sp_addextendedproperty - 'MS_Description', N'主键', - 'SCHEMA', N'dbo', - 'TABLE', N'test_tree', - 'COLUMN', N'id' -GO - -EXEC sp_addextendedproperty - 'MS_Description', N'租户id', - 'SCHEMA', N'dbo', - 'TABLE', N'test_tree', - 'COLUMN', N'tenant_id' -GO - -EXEC sp_addextendedproperty - 'MS_Description', N'父id', - 'SCHEMA', N'dbo', - 'TABLE', N'test_tree', - 'COLUMN', N'parent_id' -GO - -EXEC sp_addextendedproperty - 'MS_Description', N'部门id', - 'SCHEMA', N'dbo', - 'TABLE', N'test_tree', - 'COLUMN', N'dept_id' -GO - -EXEC sp_addextendedproperty - 'MS_Description', N'用户id', - 'SCHEMA', N'dbo', - 'TABLE', N'test_tree', - 'COLUMN', N'user_id' -GO - -EXEC sp_addextendedproperty - 'MS_Description', N'值', - 'SCHEMA', N'dbo', - 'TABLE', N'test_tree', - 'COLUMN', N'tree_name' -GO - -EXEC sp_addextendedproperty - 'MS_Description', N'版本', - 'SCHEMA', N'dbo', - 'TABLE', N'test_tree', - 'COLUMN', N'version' -GO - -EXEC sys.sp_addextendedproperty - 'MS_Description', N'创建部门' , - 'SCHEMA', N'dbo', - 'TABLE', N'test_tree', - 'COLUMN', N'create_dept' -GO - -EXEC sp_addextendedproperty - 'MS_Description', N'创建时间', - 'SCHEMA', N'dbo', - 'TABLE', N'test_tree', - 'COLUMN', N'create_time' -GO - -EXEC sp_addextendedproperty - 'MS_Description', N'创建人', - 'SCHEMA', N'dbo', - 'TABLE', N'test_tree', - 'COLUMN', N'create_by' -GO - -EXEC sp_addextendedproperty - 'MS_Description', N'更新时间', - 'SCHEMA', N'dbo', - 'TABLE', N'test_tree', - 'COLUMN', N'update_time' -GO - -EXEC sp_addextendedproperty - 'MS_Description', N'更新人', - 'SCHEMA', N'dbo', - 'TABLE', N'test_tree', - 'COLUMN', N'update_by' -GO - -EXEC sp_addextendedproperty - 'MS_Description', N'删除标志', - 'SCHEMA', N'dbo', - 'TABLE', N'test_tree', - 'COLUMN', N'del_flag' -GO - -EXEC sp_addextendedproperty - 'MS_Description', N'测试树表', - 'SCHEMA', N'dbo', - 'TABLE', N'test_tree' -GO - -INSERT sys_user VALUES (3, N'000000', 108, N'test', N'本部门及以下 密码666666', N'sys_user', N'', N'', N'0', NULL, N'$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', N'0', N'0', N'127.0.0.1', getdate(), 103, 1, getdate(), 3, getdate(), NULL); -GO -INSERT sys_user VALUES (4, N'000000', 102, N'test1', N'仅本人 密码666666', N'sys_user', N'', N'', N'0', NULL, N'$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', N'0', N'0', N'127.0.0.1', getdate(), 103, 1, getdate(), 4, getdate(), NULL); -GO - -INSERT sys_menu VALUES (5, N'测试菜单', 0, 5, N'demo', NULL, 1, 0, N'M', N'0', N'0', NULL, N'star', 103, 1, getdate(), NULL, NULL, N''); -GO - -INSERT sys_menu VALUES (1500, N'测试单表', 5, 1, N'demo', N'demo/demo/index', 1, 0, N'C', N'0', N'0', N'demo:demo:list', N'#', 103, 1, getdate(), NULL, NULL, N'测试单表菜单'); -GO -INSERT sys_menu VALUES (1501, N'测试单表查询', 1500, 1, N'#', N'', 1, 0, N'F', N'0', N'0', N'demo:demo:query', N'#', 103, 1, getdate(), NULL, NULL, N''); -GO -INSERT sys_menu VALUES (1502, N'测试单表新增', 1500, 2, N'#', N'', 1, 0, N'F', N'0', N'0', N'demo:demo:add', N'#', 103, 1, getdate(), NULL, NULL, N''); -GO -INSERT sys_menu VALUES (1503, N'测试单表修改', 1500, 3, N'#', N'', 1, 0, N'F', N'0', N'0', N'demo:demo:edit', N'#', 103, 1, getdate(), NULL, NULL, N''); -GO -INSERT sys_menu VALUES (1504, N'测试单表删除', 1500, 4, N'#', N'', 1, 0, N'F', N'0', N'0', N'demo:demo:remove', N'#', 103, 1, getdate(), NULL, NULL, N''); -GO -INSERT sys_menu VALUES (1505, N'测试单表导出', 1500, 5, N'#', N'', 1, 0, N'F', N'0', N'0', N'demo:demo:export', N'#', 103, 1, getdate(), NULL, NULL, N''); -GO - -INSERT sys_menu VALUES (1506, N'测试树表', 5, 1, N'tree', N'demo/tree/index', 1, 0, N'C', N'0', N'0', N'demo:tree:list', N'#', 103, 1, getdate(), NULL, NULL, N'测试树表菜单'); -GO -INSERT sys_menu VALUES (1507, N'测试树表查询', 1506, 1, N'#', N'', 1, 0, N'F', N'0', N'0', N'demo:tree:query', N'#', 103, 1, getdate(), NULL, NULL, N''); -GO -INSERT sys_menu VALUES (1508, N'测试树表新增', 1506, 2, N'#', N'', 1, 0, N'F', N'0', N'0', N'demo:tree:add', N'#', 103, 1, getdate(), NULL, NULL, N''); -GO -INSERT sys_menu VALUES (1509, N'测试树表修改', 1506, 3, N'#', N'', 1, 0, N'F', N'0', N'0', N'demo:tree:edit', N'#', 103, 1, getdate(), NULL, NULL, N''); -GO -INSERT sys_menu VALUES (1510, N'测试树表删除', 1506, 4, N'#', N'', 1, 0, N'F', N'0', N'0', N'demo:tree:remove', N'#', 103, 1, getdate(), NULL, NULL, N''); -GO -INSERT sys_menu VALUES (1511, N'测试树表导出', 1506, 5, N'#', N'', 1, 0, N'F', N'0', N'0', N'demo:tree:export', N'#', 103, 1, getdate(), NULL, NULL, N''); -GO - -INSERT sys_role VALUES (3, N'000000', N'本部门及以下', N'test1', 3, N'4', 1, 1, N'0', N'0', 103, 1, getdate(), 1, NULL, NULL); -GO -INSERT sys_role VALUES (4, N'000000', N'仅本人', N'test2', 4, N'5', 1, 1, N'0', N'0', 103, 1, getdate(), 1, NULL, NULL); -GO - -INSERT sys_role_menu VALUES (3, 1); -GO -INSERT sys_role_menu VALUES (3, 5); -GO -INSERT sys_role_menu VALUES (3, 100); -GO -INSERT sys_role_menu VALUES (3, 101); -GO -INSERT sys_role_menu VALUES (3, 102); -GO -INSERT sys_role_menu VALUES (3, 103); -GO -INSERT sys_role_menu VALUES (3, 104); -GO -INSERT sys_role_menu VALUES (3, 105); -GO -INSERT sys_role_menu VALUES (3, 106); -GO -INSERT sys_role_menu VALUES (3, 107); -GO -INSERT sys_role_menu VALUES (3, 108); -GO -INSERT sys_role_menu VALUES (3, 500); -GO -INSERT sys_role_menu VALUES (3, 501); -GO -INSERT sys_role_menu VALUES (3, 1001); -GO -INSERT sys_role_menu VALUES (3, 1002); -GO -INSERT sys_role_menu VALUES (3, 1003); -GO -INSERT sys_role_menu VALUES (3, 1004); -GO -INSERT sys_role_menu VALUES (3, 1005); -GO -INSERT sys_role_menu VALUES (3, 1006); -GO -INSERT sys_role_menu VALUES (3, 1007); -GO -INSERT sys_role_menu VALUES (3, 1008); -GO -INSERT sys_role_menu VALUES (3, 1009); -GO -INSERT sys_role_menu VALUES (3, 1010); -GO -INSERT sys_role_menu VALUES (3, 1011); -GO -INSERT sys_role_menu VALUES (3, 1012); -GO -INSERT sys_role_menu VALUES (3, 1013); -GO -INSERT sys_role_menu VALUES (3, 1014); -GO -INSERT sys_role_menu VALUES (3, 1015); -GO -INSERT sys_role_menu VALUES (3, 1016); -GO -INSERT sys_role_menu VALUES (3, 1017); -GO -INSERT sys_role_menu VALUES (3, 1018); -GO -INSERT sys_role_menu VALUES (3, 1019); -GO -INSERT sys_role_menu VALUES (3, 1020); -GO -INSERT sys_role_menu VALUES (3, 1021); -GO -INSERT sys_role_menu VALUES (3, 1022); -GO -INSERT sys_role_menu VALUES (3, 1023); -GO -INSERT sys_role_menu VALUES (3, 1024); -GO -INSERT sys_role_menu VALUES (3, 1025); -GO -INSERT sys_role_menu VALUES (3, 1026); -GO -INSERT sys_role_menu VALUES (3, 1027); -GO -INSERT sys_role_menu VALUES (3, 1028); -GO -INSERT sys_role_menu VALUES (3, 1029); -GO -INSERT sys_role_menu VALUES (3, 1030); -GO -INSERT sys_role_menu VALUES (3, 1031); -GO -INSERT sys_role_menu VALUES (3, 1032); -GO -INSERT sys_role_menu VALUES (3, 1033); -GO -INSERT sys_role_menu VALUES (3, 1034); -GO -INSERT sys_role_menu VALUES (3, 1035); -GO -INSERT sys_role_menu VALUES (3, 1036); -GO -INSERT sys_role_menu VALUES (3, 1037); -GO -INSERT sys_role_menu VALUES (3, 1038); -GO -INSERT sys_role_menu VALUES (3, 1039); -GO -INSERT sys_role_menu VALUES (3, 1040); -GO -INSERT sys_role_menu VALUES (3, 1041); -GO -INSERT sys_role_menu VALUES (3, 1042); -GO -INSERT sys_role_menu VALUES (3, 1043); -GO -INSERT sys_role_menu VALUES (3, 1044); -GO -INSERT sys_role_menu VALUES (3, 1045); -GO -INSERT sys_role_menu VALUES (3, 1500); -GO -INSERT sys_role_menu VALUES (3, 1501); -GO -INSERT sys_role_menu VALUES (3, 1502); -GO -INSERT sys_role_menu VALUES (3, 1503); -GO -INSERT sys_role_menu VALUES (3, 1504); -GO -INSERT sys_role_menu VALUES (3, 1505); -GO -INSERT sys_role_menu VALUES (3, 1506); -GO -INSERT sys_role_menu VALUES (3, 1507); -GO -INSERT sys_role_menu VALUES (3, 1508); -GO -INSERT sys_role_menu VALUES (3, 1509); -GO -INSERT sys_role_menu VALUES (3, 1510); -GO -INSERT sys_role_menu VALUES (3, 1511); -GO -INSERT sys_role_menu VALUES (4, 5); -GO -INSERT sys_role_menu VALUES (4, 1500); -GO -INSERT sys_role_menu VALUES (4, 1501); -GO -INSERT sys_role_menu VALUES (4, 1502); -GO -INSERT sys_role_menu VALUES (4, 1503); -GO -INSERT sys_role_menu VALUES (4, 1504); -GO -INSERT sys_role_menu VALUES (4, 1505); -GO -INSERT sys_role_menu VALUES (4, 1506); -GO -INSERT sys_role_menu VALUES (4, 1507); -GO -INSERT sys_role_menu VALUES (4, 1508); -GO -INSERT sys_role_menu VALUES (4, 1509); -GO -INSERT sys_role_menu VALUES (4, 1510); -GO -INSERT sys_role_menu VALUES (4, 1511); -GO - -INSERT sys_user_role VALUES (3, 3); -GO -INSERT sys_user_role VALUES (4, 4); -GO - -INSERT test_demo VALUES (1, N'000000', 102, 4, 1, N'测试数据权限', N'测试', 0, 103, getdate(), 1, NULL, NULL, 0); -GO -INSERT test_demo VALUES (2, N'000000', 102, 3, 2, N'子节点1', N'111', 0, 103, getdate(), 1, NULL, NULL, 0); -GO -INSERT test_demo VALUES (3, N'000000', 102, 3, 3, N'子节点2', N'222', 0, 103, getdate(), 1, NULL, NULL, 0); -GO -INSERT test_demo VALUES (4, N'000000', 108, 4, 4, N'测试数据', N'demo', 0, 103, getdate(), 1, NULL, NULL, 0); -GO -INSERT test_demo VALUES (5, N'000000', 108, 3, 13, N'子节点11', N'1111', 0, 103, getdate(), 1, NULL, NULL, 0); -GO -INSERT test_demo VALUES (6, N'000000', 108, 3, 12, N'子节点22', N'2222', 0, 103, getdate(), 1, NULL, NULL, 0); -GO -INSERT test_demo VALUES (7, N'000000', 108, 3, 11, N'子节点33', N'3333', 0, 103, getdate(), 1, NULL, NULL, 0); -GO -INSERT test_demo VALUES (8, N'000000', 108, 3, 10, N'子节点44', N'4444', 0, 103, getdate(), 1, NULL, NULL, 0); -GO -INSERT test_demo VALUES (9, N'000000', 108, 3, 9, N'子节点55', N'5555', 0, 103, getdate(), 1, NULL, NULL, 0); -GO -INSERT test_demo VALUES (10, N'000000', 108, 3, 8, N'子节点66', N'6666', 0, 103, getdate(), 1, NULL, NULL, 0); -GO -INSERT test_demo VALUES (11, N'000000', 108, 3, 7, N'子节点77', N'7777', 0, 103, getdate(), 1, NULL, NULL, 0); -GO -INSERT test_demo VALUES (12, N'000000', 108, 3, 6, N'子节点88', N'8888', 0, 103, getdate(), 1, NULL, NULL, 0); -GO -INSERT test_demo VALUES (13, N'000000', 108, 3, 5, N'子节点99', N'9999', 0, 103, getdate(), 1, NULL, NULL, 0); -GO - -INSERT test_tree VALUES (1, N'000000', 0, 102, 4, N'测试数据权限', 0, 103, getdate(), 1, NULL, NULL, 0); -GO -INSERT test_tree VALUES (2, N'000000', 1, 102, 3, N'子节点1', 0, 103, getdate(), 1, NULL, NULL, 0); -GO -INSERT test_tree VALUES (3, N'000000', 2, 102, 3, N'子节点2', 0, 103, getdate(), 1, NULL, NULL, 0); -GO -INSERT test_tree VALUES (4, N'000000', 0, 108, 4, N'测试树1', 0, 103, getdate(), 1, NULL, NULL, 0); -GO -INSERT test_tree VALUES (5, N'000000', 4, 108, 3, N'子节点11', 0, 103, getdate(), 1, NULL, NULL, 0); -GO -INSERT test_tree VALUES (6, N'000000', 4, 108, 3, N'子节点22', 0, 103, getdate(), 1, NULL, NULL, 0); -GO -INSERT test_tree VALUES (7, N'000000', 4, 108, 3, N'子节点33', 0, 103, getdate(), 1, NULL, NULL, 0); -GO -INSERT test_tree VALUES (8, N'000000', 5, 108, 3, N'子节点44', 0, 103, getdate(), 1, NULL, NULL, 0); -GO -INSERT test_tree VALUES (9, N'000000', 6, 108, 3, N'子节点55', 0, 103, getdate(), 1, NULL, NULL, 0); -GO -INSERT test_tree VALUES (10, N'000000', 7, 108, 3, N'子节点66', 0, 103, getdate(), 1, NULL, NULL, 0); -GO -INSERT test_tree VALUES (11, N'000000', 7, 108, 3, N'子节点77', 0, 103, getdate(), 1, NULL, NULL, 0); -GO -INSERT test_tree VALUES (12, N'000000', 10, 108, 3, N'子节点88', 0, 103, getdate(), 1, NULL, NULL, 0); -GO -INSERT test_tree VALUES (13, N'000000', 10, 108, 3, N'子节点99', 0, 103, getdate(), 1, NULL, NULL, 0); -GO diff --git a/script/sql/test.sql b/script/sql/test.sql deleted file mode 100644 index d4cea0567..000000000 --- a/script/sql/test.sql +++ /dev/null @@ -1,175 +0,0 @@ -DROP TABLE if EXISTS test_demo; -CREATE TABLE test_demo -( - id bigint(0) NOT NULL COMMENT '主键', - tenant_id varchar(20) NULL DEFAULT '000000' COMMENT '租户编号', - dept_id bigint(0) NULL DEFAULT NULL COMMENT '部门id', - user_id bigint(0) NULL DEFAULT NULL COMMENT '用户id', - order_num int(0) NULL DEFAULT 0 COMMENT '排序号', - test_key varchar(255) NULL DEFAULT NULL COMMENT 'key键', - value varchar(255) NULL DEFAULT NULL COMMENT '值', - version int(0) NULL DEFAULT 0 COMMENT '版本', - create_dept bigint(0) NULL DEFAULT NULL COMMENT '创建部门', - create_time datetime(0) NULL DEFAULT NULL COMMENT '创建时间', - create_by bigint(0) NULL DEFAULT NULL COMMENT '创建人', - update_time datetime(0) NULL DEFAULT NULL COMMENT '更新时间', - update_by bigint(0) NULL DEFAULT NULL COMMENT '更新人', - del_flag int(0) NULL DEFAULT 0 COMMENT '删除标志', - PRIMARY KEY (id) USING BTREE -) ENGINE = InnoDB COMMENT = '测试单表'; - -DROP TABLE if EXISTS test_tree; -CREATE TABLE test_tree -( - id bigint(0) NOT NULL COMMENT '主键', - tenant_id varchar(20) NULL DEFAULT '000000' COMMENT '租户编号', - parent_id bigint(0) NULL DEFAULT 0 COMMENT '父id', - dept_id bigint(0) NULL DEFAULT NULL COMMENT '部门id', - user_id bigint(0) NULL DEFAULT NULL COMMENT '用户id', - tree_name varchar(255) NULL DEFAULT NULL COMMENT '值', - version int(0) NULL DEFAULT 0 COMMENT '版本', - create_dept bigint(0) NULL DEFAULT NULL COMMENT '创建部门', - create_time datetime(0) NULL DEFAULT NULL COMMENT '创建时间', - create_by bigint(0) NULL DEFAULT NULL COMMENT '创建人', - update_time datetime(0) NULL DEFAULT NULL COMMENT '更新时间', - update_by bigint(0) NULL DEFAULT NULL COMMENT '更新人', - del_flag int(0) NULL DEFAULT 0 COMMENT '删除标志', - PRIMARY KEY (id) USING BTREE -) ENGINE = InnoDB COMMENT = '测试树表'; - -INSERT INTO sys_user(user_id, tenant_id, dept_id, user_name, nick_name, user_type, email, phonenumber, sex, avatar, password, status, del_flag, login_ip, login_date, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (3, '000000', 108, 'test', '本部门及以下 密码666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', sysdate(), 103, 1, sysdate(), 3, sysdate(), NULL); -INSERT INTO sys_user(user_id, tenant_id, dept_id, user_name, nick_name, user_type, email, phonenumber, sex, avatar, password, status, del_flag, login_ip, login_date, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (4, '000000', 102, 'test1', '仅本人 密码666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', sysdate(), 103, 1, sysdate(), 4, sysdate(), NULL); - -INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (5, '测试菜单', 0, 5, 'demo', NULL, 1, 0, 'M', '0', '0', NULL, 'star', 103, 1, sysdate(), NULL, NULL, ''); - -INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (1500, '测试单表', 5, 1, 'demo', 'demo/demo/index', 1, 0, 'C', '0', '0', 'demo:demo:list', '#', 103, 1, sysdate(), NULL, NULL, '测试单表菜单'); -INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (1501, '测试单表查询', 1500, 1, '#', '', 1, 0, 'F', '0', '0', 'demo:demo:query', '#', 103, 1, sysdate(), NULL, NULL, ''); -INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (1502, '测试单表新增', 1500, 2, '#', '', 1, 0, 'F', '0', '0', 'demo:demo:add', '#', 103, 1, sysdate(), NULL, NULL, ''); -INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (1503, '测试单表修改', 1500, 3, '#', '', 1, 0, 'F', '0', '0', 'demo:demo:edit', '#', 103, 1, sysdate(), NULL, NULL, ''); -INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (1504, '测试单表删除', 1500, 4, '#', '', 1, 0, 'F', '0', '0', 'demo:demo:remove', '#', 103, 1, sysdate(), NULL, NULL, ''); -INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (1505, '测试单表导出', 1500, 5, '#', '', 1, 0, 'F', '0', '0', 'demo:demo:export', '#', 103, 1, sysdate(), NULL, NULL, ''); - -INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (1506, '测试树表', 5, 1, 'tree', 'demo/tree/index', 1, 0, 'C', '0', '0', 'demo:tree:list', '#', 103, 1, sysdate(), NULL, NULL, '测试树表菜单'); -INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (1507, '测试树表查询', 1506, 1, '#', '', 1, 0, 'F', '0', '0', 'demo:tree:query', '#', 103, 1, sysdate(), NULL, NULL, ''); -INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (1508, '测试树表新增', 1506, 2, '#', '', 1, 0, 'F', '0', '0', 'demo:tree:add', '#', 103, 1, sysdate(), NULL, NULL, ''); -INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (1509, '测试树表修改', 1506, 3, '#', '', 1, 0, 'F', '0', '0', 'demo:tree:edit', '#', 103, 1, sysdate(), NULL, NULL, ''); -INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (1510, '测试树表删除', 1506, 4, '#', '', 1, 0, 'F', '0', '0', 'demo:tree:remove', '#', 103, 1, sysdate(), NULL, NULL, ''); -INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (1511, '测试树表导出', 1506, 5, '#', '', 1, 0, 'F', '0', '0', 'demo:tree:export', '#', 103, 1, sysdate(), NULL, NULL, ''); - -INSERT INTO sys_role(role_id, tenant_id, role_name, role_key, role_sort, data_scope, menu_check_strictly, dept_check_strictly, status, del_flag, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (3, '000000', '本部门及以下', 'test1', 3, '4', 1, 1, '0', '0', 103, 1, sysdate(), 1, NULL, NULL); -INSERT INTO sys_role(role_id, tenant_id, role_name, role_key, role_sort, data_scope, menu_check_strictly, dept_check_strictly, status, del_flag, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (4, '000000', '仅本人', 'test2', 4, '5', 1, 1, '0', '0', 103, 1, sysdate(), 1, NULL, NULL); - -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 5); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 100); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 101); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 102); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 103); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 104); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 105); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 106); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 107); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 108); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 500); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 501); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1001); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1002); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1003); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1004); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1005); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1006); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1007); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1008); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1009); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1010); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1011); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1012); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1013); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1014); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1015); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1016); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1017); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1018); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1019); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1020); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1021); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1022); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1023); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1024); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1025); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1026); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1027); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1028); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1029); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1030); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1031); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1032); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1033); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1034); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1035); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1036); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1037); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1038); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1039); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1040); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1041); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1042); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1043); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1044); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1045); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1500); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1501); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1502); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1503); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1504); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1505); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1506); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1507); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1508); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1509); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1510); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (3, 1511); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (4, 5); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (4, 1500); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (4, 1501); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (4, 1502); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (4, 1503); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (4, 1504); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (4, 1505); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (4, 1506); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (4, 1507); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (4, 1508); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (4, 1509); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (4, 1510); -INSERT INTO sys_role_menu(role_id, menu_id) VALUES (4, 1511); - -INSERT INTO sys_user_role(user_id, role_id) VALUES (3, 3); -INSERT INTO sys_user_role(user_id, role_id) VALUES (4, 4); - -INSERT INTO test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (1, '000000', 102, 4, 1, '测试数据权限', '测试', 0, 103, sysdate(), 1, NULL, NULL, 0); -INSERT INTO test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (2, '000000', 102, 3, 2, '子节点1', '111', 0, 103, sysdate(), 1, NULL, NULL, 0); -INSERT INTO test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (3, '000000', 102, 3, 3, '子节点2', '222', 0, 103, sysdate(), 1, NULL, NULL, 0); -INSERT INTO test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (4, '000000', 108, 4, 4, '测试数据', 'demo', 0, 103, sysdate(), 1, NULL, NULL, 0); -INSERT INTO test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (5, '000000', 108, 3, 13, '子节点11', '1111', 0, 103, sysdate(), 1, NULL, NULL, 0); -INSERT INTO test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (6, '000000', 108, 3, 12, '子节点22', '2222', 0, 103, sysdate(), 1, NULL, NULL, 0); -INSERT INTO test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (7, '000000', 108, 3, 11, '子节点33', '3333', 0, 103, sysdate(), 1, NULL, NULL, 0); -INSERT INTO test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (8, '000000', 108, 3, 10, '子节点44', '4444', 0, 103, sysdate(), 1, NULL, NULL, 0); -INSERT INTO test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (9, '000000', 108, 3, 9, '子节点55', '5555', 0, 103, sysdate(), 1, NULL, NULL, 0); -INSERT INTO test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (10, '000000', 108, 3, 8, '子节点66', '6666', 0, 103, sysdate(), 1, NULL, NULL, 0); -INSERT INTO test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (11, '000000', 108, 3, 7, '子节点77', '7777', 0, 103, sysdate(), 1, NULL, NULL, 0); -INSERT INTO test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (12, '000000', 108, 3, 6, '子节点88', '8888', 0, 103, sysdate(), 1, NULL, NULL, 0); -INSERT INTO test_demo(id, tenant_id, dept_id, user_id, order_num, test_key, value, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (13, '000000', 108, 3, 5, '子节点99', '9999', 0, 103, sysdate(), 1, NULL, NULL, 0); - -INSERT INTO test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (1, '000000', 0, 102, 4, '测试数据权限', 0, 103, sysdate(), 1, NULL, NULL, 0); -INSERT INTO test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (2, '000000', 1, 102, 3, '子节点1', 0, 103, sysdate(), 1, NULL, NULL, 0); -INSERT INTO test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (3, '000000', 2, 102, 3, '子节点2', 0, 103, sysdate(), 1, NULL, NULL, 0); -INSERT INTO test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (4, '000000', 0, 108, 4, '测试树1', 0, 103, sysdate(), 1, NULL, NULL, 0); -INSERT INTO test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (5, '000000', 4, 108, 3, '子节点11', 0, 103, sysdate(), 1, NULL, NULL, 0); -INSERT INTO test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (6, '000000', 4, 108, 3, '子节点22', 0, 103, sysdate(), 1, NULL, NULL, 0); -INSERT INTO test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (7, '000000', 4, 108, 3, '子节点33', 0, 103, sysdate(), 1, NULL, NULL, 0); -INSERT INTO test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (8, '000000', 5, 108, 3, '子节点44', 0, 103, sysdate(), 1, NULL, NULL, 0); -INSERT INTO test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (9, '000000', 6, 108, 3, '子节点55', 0, 103, sysdate(), 1, NULL, NULL, 0); -INSERT INTO test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (10, '000000', 7, 108, 3, '子节点66', 0, 103, sysdate(), 1, NULL, NULL, 0); -INSERT INTO test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (11, '000000', 7, 108, 3, '子节点77', 0, 103, sysdate(), 1, NULL, NULL, 0); -INSERT INTO test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (12, '000000', 10, 108, 3, '子节点88', 0, 103, sysdate(), 1, NULL, NULL, 0); -INSERT INTO test_tree(id, tenant_id, parent_id, dept_id, user_id, tree_name, version, create_dept, create_time, create_by, update_time, update_by, del_flag) VALUES (13, '000000', 10, 108, 3, '子节点99', 0, 103, sysdate(), 1, NULL, NULL, 0);