diff --git a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/config/AuthorizationServerConfiguration.java b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/config/AuthorizationServerConfiguration.java index 678a73abe..51b56f01e 100644 --- a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/config/AuthorizationServerConfiguration.java +++ b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/config/AuthorizationServerConfiguration.java @@ -48,6 +48,7 @@ import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.AuthenticationConverter; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import java.util.Arrays; @@ -79,9 +80,13 @@ public class AuthorizationServerConfiguration { .authorizationEndpoint(authorizationEndpoint -> authorizationEndpoint// 授权码端点个性化confirm页面 .consentPage(SecurityConstants.CUSTOM_CONSENT_PAGE_URI))); + AntPathRequestMatcher[] requestMatchers = new AntPathRequestMatcher[] { + AntPathRequestMatcher.antMatcher("/token/**"), AntPathRequestMatcher.antMatcher("/actuator/**"), + AntPathRequestMatcher.antMatcher("/css/**"), AntPathRequestMatcher.antMatcher("/error") }; + http.authorizeHttpRequests(authorizeRequests -> { // 自定义接口、端点暴露 - authorizeRequests.requestMatchers("/token/**", "/actuator/**", "/css/**", "/error").permitAll(); + authorizeRequests.requestMatchers(requestMatchers).permitAll(); authorizeRequests.anyRequest().authenticated(); }) .apply(authorizationServerConfigurer.authorizationService(authorizationService)// redis存储token的实现 diff --git a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/endpoint/PigxTokenEndpoint.java b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/endpoint/PigxTokenEndpoint.java index 8fe3bf0d5..0be207956 100644 --- a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/endpoint/PigxTokenEndpoint.java +++ b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/endpoint/PigxTokenEndpoint.java @@ -38,6 +38,8 @@ import com.pig4cloud.pigx.common.security.annotation.Inner; import com.pig4cloud.pigx.common.security.service.PigxUser; import com.pig4cloud.pigx.common.security.util.OAuth2ErrorCodesExpand; import com.pig4cloud.pigx.common.security.util.OAuthClientException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; @@ -59,8 +61,6 @@ import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.ModelAndView; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; import java.security.Principal; import java.util.List; import java.util.Map; @@ -114,8 +114,9 @@ public class PigxTokenEndpoint { @RequestParam(OAuth2ParameterNames.SCOPE) String scope, @RequestParam(OAuth2ParameterNames.STATE) String state) { SysOauthClientDetails clientDetails = RetOps - .of(clientDetailsService.getClientDetailsById(clientId, SecurityConstants.FROM_IN)).getData() - .orElseThrow(() -> new OAuthClientException("clientId 不合法")); + .of(clientDetailsService.getClientDetailsById(clientId, SecurityConstants.FROM_IN)) + .getData() + .orElseThrow(() -> new OAuthClientException("clientId 不合法")); Set authorizedScopes = StringUtils.commaDelimitedListToSet(clientDetails.getScope()); modelAndView.addObject("clientId", clientId); diff --git a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/CustomeOAuth2AccessTokenGenerator.java b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/CustomeOAuth2AccessTokenGenerator.java index 54f6f26e6..72a1aa514 100644 --- a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/CustomeOAuth2AccessTokenGenerator.java +++ b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/CustomeOAuth2AccessTokenGenerator.java @@ -30,7 +30,7 @@ public class CustomeOAuth2AccessTokenGenerator implements OAuth2TokenGenerator additionalParameters = parameters.entrySet().stream() - .filter(e -> !e.getKey().equals(OAuth2ParameterNames.GRANT_TYPE) - && !e.getKey().equals(OAuth2ParameterNames.SCOPE)) - .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().get(0))); + Map additionalParameters = parameters.entrySet() + .stream() + .filter(e -> !e.getKey().equals(OAuth2ParameterNames.GRANT_TYPE) + && !e.getKey().equals(OAuth2ParameterNames.SCOPE)) + .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().get(0))); // 创建token return buildToken(clientPrincipal, requestedScopes, additionalParameters); diff --git a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/core/FormIdentityLoginConfigurer.java b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/core/FormIdentityLoginConfigurer.java index 88965f096..0d790965b 100644 --- a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/core/FormIdentityLoginConfigurer.java +++ b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/core/FormIdentityLoginConfigurer.java @@ -23,9 +23,14 @@ public final class FormIdentityLoginConfigurer formLogin.failureHandler(new FormAuthenticationFailureHandler()); formLogin.successHandler(new TenantSavedRequestAwareAuthenticationSuccessHandler()); - }).logout() // SSO登出成功处理 - .logoutSuccessHandler(new SsoLogoutSuccessHandler()).deleteCookies("JSESSIONID") - .invalidateHttpSession(true).and().csrf().disable(); + }) + .logout() // SSO登出成功处理 + .logoutSuccessHandler(new SsoLogoutSuccessHandler()) + .deleteCookies("JSESSIONID") + .invalidateHttpSession(true) + .and() + .csrf() + .disable(); } } diff --git a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/core/PigxDaoAuthenticationProvider.java b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/core/PigxDaoAuthenticationProvider.java index 1798e7c48..741037b38 100644 --- a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/core/PigxDaoAuthenticationProvider.java +++ b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/core/PigxDaoAuthenticationProvider.java @@ -74,13 +74,13 @@ public class PigxDaoAuthenticationProvider extends AbstractUserDetailsAuthentica if (authentication.getCredentials() == null) { this.logger.debug("Failed to authenticate since no credentials provided"); throw new BadCredentialsException(this.messages - .getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); + .getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); } String presentedPassword = authentication.getCredentials().toString(); if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) { this.logger.debug("Failed to authenticate since password does not match stored value"); throw new BadCredentialsException(this.messages - .getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); + .getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); } } @@ -96,14 +96,15 @@ public class PigxDaoAuthenticationProvider extends AbstractUserDetailsAuthentica } Map userDetailsServiceMap = SpringUtil - .getBeansOfType(PigxUserDetailsService.class); + .getBeansOfType(PigxUserDetailsService.class); String finalClientId = clientId; - Optional optional = userDetailsServiceMap.values().stream() - .filter(service -> service.support(finalClientId, grantType)) - .max(Comparator.comparingInt(Ordered::getOrder)); + Optional optional = userDetailsServiceMap.values() + .stream() + .filter(service -> service.support(finalClientId, grantType)) + .max(Comparator.comparingInt(Ordered::getOrder)); - if (!optional.isPresent()) { + if (optional.isEmpty()) { throw new InternalAuthenticationServiceException("UserDetailsService error , not register"); } diff --git a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/handler/PigxAuthenticationSuccessEventHandler.java b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/handler/PigxAuthenticationSuccessEventHandler.java index e653e6a8a..3f773a649 100644 --- a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/handler/PigxAuthenticationSuccessEventHandler.java +++ b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/handler/PigxAuthenticationSuccessEventHandler.java @@ -26,6 +26,8 @@ import com.pig4cloud.pigx.common.core.util.KeyStrResolver; import com.pig4cloud.pigx.common.log.event.SysLogEvent; import com.pig4cloud.pigx.common.log.util.LogTypeEnum; import com.pig4cloud.pigx.common.log.util.SysLogUtils; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; @@ -45,8 +47,6 @@ import org.springframework.security.web.authentication.AuthenticationSuccessHand import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.time.temporal.ChronoUnit; import java.util.Map; @@ -145,7 +145,8 @@ public class PigxAuthenticationSuccessEventHandler implements AuthenticationSucc Map additionalParameters = accessTokenAuthentication.getAdditionalParameters(); OAuth2AccessTokenResponse.Builder builder = OAuth2AccessTokenResponse.withToken(accessToken.getTokenValue()) - .tokenType(accessToken.getTokenType()).scopes(accessToken.getScopes()); + .tokenType(accessToken.getTokenType()) + .scopes(accessToken.getScopes()); if (accessToken.getIssuedAt() != null && accessToken.getExpiresAt() != null) { builder.expiresIn(ChronoUnit.SECONDS.between(accessToken.getIssuedAt(), accessToken.getExpiresAt())); } diff --git a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/sms/OAuth2ResourceOwnerSmsAuthenticationProvider.java b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/sms/OAuth2ResourceOwnerSmsAuthenticationProvider.java index 961f1e9e1..a480b7e4d 100644 --- a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/sms/OAuth2ResourceOwnerSmsAuthenticationProvider.java +++ b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/sms/OAuth2ResourceOwnerSmsAuthenticationProvider.java @@ -52,7 +52,7 @@ public class OAuth2ResourceOwnerSmsAuthenticationProvider public void checkClient(RegisteredClient registeredClient) { assert registeredClient != null; if (!registeredClient.getAuthorizationGrantTypes() - .contains(new AuthorizationGrantType(SecurityConstants.APP))) { + .contains(new AuthorizationGrantType(SecurityConstants.APP))) { throw new OAuth2AuthenticationException(OAuth2ErrorCodes.UNAUTHORIZED_CLIENT); } } diff --git a/pigx-common/pigx-common-bom/pom.xml b/pigx-common/pigx-common-bom/pom.xml index 9330c2bc1..29453a690 100644 --- a/pigx-common/pigx-common-bom/pom.xml +++ b/pigx-common/pigx-common-bom/pom.xml @@ -35,6 +35,7 @@ 2.9.6-17 3.0.3 1.13.1 + 5.3.3 7.0.0.M1 2.3.6.RELEASE 1.2.83 @@ -166,7 +167,13 @@ com.pig4cloud - pigx-flowable-api + pigx-flow-task-api + ${pigx.version} + + + + com.pig4cloud + pigx-flow-engine-api ${pigx.version} @@ -256,6 +263,12 @@ fastjson ${fastjson.version} + + + com.googlecode.aviator + aviator + ${aviator.version} + org.javers diff --git a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/ServiceNameConstants.java b/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/ServiceNameConstants.java index 3ee3d48ce..f4f0d0723 100644 --- a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/ServiceNameConstants.java +++ b/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/ServiceNameConstants.java @@ -35,14 +35,19 @@ public interface ServiceNameConstants { */ String UPMS_SERVICE = "pigx-upms-biz"; - /** - * 分布式事务协调服务 - */ - String TX_MANAGER = "pigx-tx-manager"; - /** * app服务 */ String APP_SERVER = "pigx-app-server-biz"; + /** + * 流程引擎 + */ + String FLOW_ENGINE_SERVER = "pigx-flow-engine-biz"; + + /** + * 流程工单 + */ + String FLOW_TASK_SERVER = "pigx-flow-task-biz"; + } diff --git a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/enums/StyleTypeEnum.java b/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/enums/StyleTypeEnum.java index f3325eb9d..82ba6c629 100644 --- a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/enums/StyleTypeEnum.java +++ b/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/enums/StyleTypeEnum.java @@ -50,8 +50,11 @@ public enum StyleTypeEnum { private String description; public static String getDecs(String style) { - return Arrays.stream(StyleTypeEnum.values()).filter(styleTypeEnum -> styleTypeEnum.getStyle().equals(style)) - .findFirst().get().getDescription(); + return Arrays.stream(StyleTypeEnum.values()) + .filter(styleTypeEnum -> styleTypeEnum.getStyle().equals(style)) + .findFirst() + .get() + .getDescription(); } } diff --git a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/sensitive/SensitiveSerialize.java b/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/sensitive/SensitiveSerialize.java index d0cf57883..b2b8797fe 100644 --- a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/sensitive/SensitiveSerialize.java +++ b/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/sensitive/SensitiveSerialize.java @@ -81,7 +81,7 @@ public class SensitiveSerialize extends JsonSerializer implements Contex break; case CUSTOMER: jsonGenerator - .writeString(DesensitizedUtils.desValue(origin, prefixNoMaskLen, suffixNoMaskLen, maskStr)); + .writeString(DesensitizedUtils.desValue(origin, prefixNoMaskLen, suffixNoMaskLen, maskStr)); break; default: throw new IllegalArgumentException("Unknow sensitive type enum " + type); diff --git a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/R.java b/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/R.java index 50db0f9e6..da9a30844 100644 --- a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/R.java +++ b/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/R.java @@ -93,4 +93,8 @@ public class R implements Serializable { return apiResult; } + public boolean isOk() { + return this.code == CommonConstants.SUCCESS; + } + } diff --git a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/DefaultRedisCacheWriter.java b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/DefaultRedisCacheWriter.java index 4a28c8f80..7014107d4 100644 --- a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/DefaultRedisCacheWriter.java +++ b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/DefaultRedisCacheWriter.java @@ -183,8 +183,9 @@ class DefaultRedisCacheWriter implements RedisCacheWriter { wasLocked = true; } - byte[][] keys = Optional.ofNullable(connection.keys(pattern)).orElse(Collections.emptySet()) - .toArray(new byte[0][]); + byte[][] keys = Optional.ofNullable(connection.keys(pattern)) + .orElse(Collections.emptySet()) + .toArray(new byte[0][]); if (keys.length > 0) { connection.del(keys); diff --git a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/RedisCacheAutoConfiguration.java b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/RedisCacheAutoConfiguration.java index 54877e89a..beb2eda4a 100644 --- a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/RedisCacheAutoConfiguration.java +++ b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/cache/RedisCacheAutoConfiguration.java @@ -90,7 +90,7 @@ public class RedisCacheAutoConfiguration { CacheProperties.Redis redisProperties = this.cacheProperties.getRedis(); RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig(); config = config.serializeValuesWith(RedisSerializationContext.SerializationPair - .fromSerializer(new JdkSerializationRedisSerializer(classLoader))); + .fromSerializer(new JdkSerializationRedisSerializer(classLoader))); if (redisProperties.getTimeToLive() != null) { config = config.entryTtl(redisProperties.getTimeToLive()); } diff --git a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/datascope/PigxDefaultDatascopeHandle.java b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/datascope/PigxDefaultDatascopeHandle.java index 547c0f439..2975dd31a 100644 --- a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/datascope/PigxDefaultDatascopeHandle.java +++ b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/datascope/PigxDefaultDatascopeHandle.java @@ -60,9 +60,12 @@ public class PigxDefaultDatascopeHandle implements DataScopeHandle { return true; } - List roleIdList = user.getAuthorities().stream().map(GrantedAuthority::getAuthority) - .filter(authority -> authority.startsWith(SecurityConstants.ROLE)) - .map(authority -> authority.split(StrUtil.UNDERLINE)[1]).collect(Collectors.toList()); + List roleIdList = user.getAuthorities() + .stream() + .map(GrantedAuthority::getAuthority) + .filter(authority -> authority.startsWith(SecurityConstants.ROLE)) + .map(authority -> authority.split(StrUtil.UNDERLINE)[1]) + .collect(Collectors.toList()); List deptList = dataScope.getDeptList(); @@ -89,8 +92,8 @@ public class PigxDefaultDatascopeHandle implements DataScopeHandle { // 自定义 if (DataScopeTypeEnum.CUSTOM.getType() == dsType && StrUtil.isNotBlank(role.getDsScope())) { String dsScope = role.getDsScope(); - deptList.addAll( - Arrays.stream(dsScope.split(StrUtil.COMMA)).map(Long::parseLong).collect(Collectors.toList())); + deptList + .addAll(Arrays.stream(dsScope.split(StrUtil.COMMA)).map(Long::parseLong).collect(Collectors.toList())); } // 查询本级及其下级 if (DataScopeTypeEnum.OWN_CHILD_LEVEL.getType() == dsType) { diff --git a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/resolver/SqlFilterArgumentResolver.java b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/resolver/SqlFilterArgumentResolver.java index c49e02ab0..60d762972 100644 --- a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/resolver/SqlFilterArgumentResolver.java +++ b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/resolver/SqlFilterArgumentResolver.java @@ -22,6 +22,7 @@ import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.metadata.OrderItem; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.pig4cloud.pigx.common.core.exception.CheckedException; +import jakarta.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; import org.springframework.core.MethodParameter; import org.springframework.web.bind.support.WebDataBinderFactory; @@ -29,7 +30,6 @@ import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; -import jakarta.servlet.http.HttpServletRequest; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -94,10 +94,16 @@ public class SqlFilterArgumentResolver implements HandlerMethodArgumentResolver } List orderItemList = new ArrayList<>(); - Optional.ofNullable(ascs).ifPresent(s -> orderItemList.addAll(Arrays.stream(s.split(StrUtil.COMMA)) - .filter(sqlInjectPredicate()).map(OrderItem::asc).collect(Collectors.toList()))); - Optional.ofNullable(descs).ifPresent(s -> orderItemList.addAll(Arrays.stream(s.split(StrUtil.COMMA)) - .filter(sqlInjectPredicate()).map(OrderItem::desc).collect(Collectors.toList()))); + Optional.ofNullable(ascs) + .ifPresent(s -> orderItemList.addAll(Arrays.stream(s.split(StrUtil.COMMA)) + .filter(sqlInjectPredicate()) + .map(OrderItem::asc) + .collect(Collectors.toList()))); + Optional.ofNullable(descs) + .ifPresent(s -> orderItemList.addAll(Arrays.stream(s.split(StrUtil.COMMA)) + .filter(sqlInjectPredicate()) + .map(OrderItem::desc) + .collect(Collectors.toList()))); page.addOrder(orderItemList); return page; diff --git a/pigx-common/pigx-common-datasource/src/main/java/com/pig4cloud/pigx/common/datasource/util/DsJdbcUrlEnum.java b/pigx-common/pigx-common-datasource/src/main/java/com/pig4cloud/pigx/common/datasource/util/DsJdbcUrlEnum.java index 0a9e8f498..7e4adc1f5 100644 --- a/pigx-common/pigx-common-datasource/src/main/java/com/pig4cloud/pigx/common/datasource/util/DsJdbcUrlEnum.java +++ b/pigx-common/pigx-common-datasource/src/main/java/com/pig4cloud/pigx/common/datasource/util/DsJdbcUrlEnum.java @@ -63,8 +63,10 @@ public enum DsJdbcUrlEnum { private final String description; public static DsJdbcUrlEnum get(String dsType) { - return Arrays.stream(DsJdbcUrlEnum.values()).filter(dsJdbcUrlEnum -> dsType.equals(dsJdbcUrlEnum.getDbName())) - .findFirst().get(); + return Arrays.stream(DsJdbcUrlEnum.values()) + .filter(dsJdbcUrlEnum -> dsType.equals(dsJdbcUrlEnum.getDbName())) + .findFirst() + .get(); } } diff --git a/pigx-common/pigx-common-gray/src/main/java/com/pig4cloud/pigx/common/gray/rule/GrayRoundRobinLoadBalancer.java b/pigx-common/pigx-common-gray/src/main/java/com/pig4cloud/pigx/common/gray/rule/GrayRoundRobinLoadBalancer.java index 4ad5f8c22..08f339d67 100755 --- a/pigx-common/pigx-common-gray/src/main/java/com/pig4cloud/pigx/common/gray/rule/GrayRoundRobinLoadBalancer.java +++ b/pigx-common/pigx-common-gray/src/main/java/com/pig4cloud/pigx/common/gray/rule/GrayRoundRobinLoadBalancer.java @@ -48,7 +48,7 @@ public class GrayRoundRobinLoadBalancer extends RoundRobinLoadBalancer { @Override public Mono> choose(Request request) { ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider - .getIfAvailable(NoopServiceInstanceListSupplier::new); + .getIfAvailable(NoopServiceInstanceListSupplier::new); return supplier.get(request).next().map(serviceInstances -> getInstanceResponse(serviceInstances, request)); } @@ -77,8 +77,8 @@ public class GrayRoundRobinLoadBalancer extends RoundRobinLoadBalancer { if (StrUtil.isBlank(reqVersion)) { // 过滤出不含VERSION实例 List versionInstanceList = instances.stream() - .filter(instance -> !instance.getMetadata().containsKey(CommonConstants.VERSION)) - .collect(Collectors.toList()); + .filter(instance -> !instance.getMetadata().containsKey(CommonConstants.VERSION)) + .collect(Collectors.toList()); if (CollUtil.isEmpty(versionInstanceList)) { // 根据权重获取实例 return new DefaultResponse(randomByWeight(instances)); diff --git a/pigx-common/pigx-common-idempotent/src/main/java/com/pig4cloud/pigx/common/idempotent/aspect/IdempotentAspect.java b/pigx-common/pigx-common-idempotent/src/main/java/com/pig4cloud/pigx/common/idempotent/aspect/IdempotentAspect.java index a4b01d871..b63493a4a 100644 --- a/pigx-common/pigx-common-idempotent/src/main/java/com/pig4cloud/pigx/common/idempotent/aspect/IdempotentAspect.java +++ b/pigx-common/pigx-common-idempotent/src/main/java/com/pig4cloud/pigx/common/idempotent/aspect/IdempotentAspect.java @@ -3,6 +3,7 @@ package com.pig4cloud.pigx.common.idempotent.aspect; import com.pig4cloud.pigx.common.idempotent.annotation.Idempotent; import com.pig4cloud.pigx.common.idempotent.exception.IdempotentException; import com.pig4cloud.pigx.common.idempotent.expression.KeyResolver; +import jakarta.servlet.http.HttpServletRequest; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; @@ -19,7 +20,6 @@ import org.springframework.util.StringUtils; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; -import jakarta.servlet.http.HttpServletRequest; import java.lang.reflect.Method; import java.time.LocalDateTime; import java.util.Arrays; @@ -58,7 +58,7 @@ public class IdempotentAspect { @Before("pointCut()") public void beforePointCut(JoinPoint joinPoint) { ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder - .getRequestAttributes(); + .getRequestAttributes(); HttpServletRequest request = requestAttributes.getRequest(); MethodSignature signature = (MethodSignature) joinPoint.getSignature(); diff --git a/pigx-common/pigx-common-idempotent/src/main/java/com/pig4cloud/pigx/common/idempotent/expression/ExpressionResolver.java b/pigx-common/pigx-common-idempotent/src/main/java/com/pig4cloud/pigx/common/idempotent/expression/ExpressionResolver.java index bcbff8566..31846b7c9 100644 --- a/pigx-common/pigx-common-idempotent/src/main/java/com/pig4cloud/pigx/common/idempotent/expression/ExpressionResolver.java +++ b/pigx-common/pigx-common-idempotent/src/main/java/com/pig4cloud/pigx/common/idempotent/expression/ExpressionResolver.java @@ -53,8 +53,9 @@ public class ExpressionResolver implements KeyResolver { Method method = signature.getMethod(); if (method.getDeclaringClass().isInterface()) { try { - method = joinPoint.getTarget().getClass().getDeclaredMethod(joinPoint.getSignature().getName(), - method.getParameterTypes()); + method = joinPoint.getTarget() + .getClass() + .getDeclaredMethod(joinPoint.getSignature().getName(), method.getParameterTypes()); } catch (SecurityException | NoSuchMethodException e) { throw new RuntimeException(e); diff --git a/pigx-common/pigx-common-job/src/main/java/com/pig4cloud/pigx/common/job/XxlJobAutoConfiguration.java b/pigx-common/pigx-common-job/src/main/java/com/pig4cloud/pigx/common/job/XxlJobAutoConfiguration.java index 260244f01..de87f0399 100644 --- a/pigx-common/pigx-common-job/src/main/java/com/pig4cloud/pigx/common/job/XxlJobAutoConfiguration.java +++ b/pigx-common/pigx-common-job/src/main/java/com/pig4cloud/pigx/common/job/XxlJobAutoConfiguration.java @@ -55,10 +55,13 @@ public class XxlJobAutoConfiguration { // 如果配置为空则获取注册中心的服务列表 "http://pigx-xxl:9080/xxl-job-admin" if (!StringUtils.hasText(xxlJobProperties.getAdmin().getAddresses())) { - String serverList = discoveryClient.getServices().stream().filter(s -> s.contains(XXL_JOB_ADMIN)) - .flatMap(s -> discoveryClient.getInstances(s).stream()).map(instance -> String - .format("http://%s:%s/%s", instance.getHost(), instance.getPort(), XXL_JOB_ADMIN)) - .collect(Collectors.joining(",")); + String serverList = discoveryClient.getServices() + .stream() + .filter(s -> s.contains(XXL_JOB_ADMIN)) + .flatMap(s -> discoveryClient.getInstances(s).stream()) + .map(instance -> String.format("http://%s:%s/%s", instance.getHost(), instance.getPort(), + XXL_JOB_ADMIN)) + .collect(Collectors.joining(",")); xxlJobSpringExecutor.setAdminAddresses(serverList); } else { diff --git a/pigx-common/pigx-common-oss/src/main/java/com/pig4cloud/pigx/common/file/local/LocalFileTemplate.java b/pigx-common/pigx-common-oss/src/main/java/com/pig4cloud/pigx/common/file/local/LocalFileTemplate.java index f330c264e..98038b73e 100644 --- a/pigx-common/pigx-common-oss/src/main/java/com/pig4cloud/pigx/common/file/local/LocalFileTemplate.java +++ b/pigx-common/pigx-common-oss/src/main/java/com/pig4cloud/pigx/common/file/local/LocalFileTemplate.java @@ -43,8 +43,10 @@ public class LocalFileTemplate implements FileTemplate { */ @Override public List getAllBuckets() { - return Arrays.stream(FileUtil.ls(properties.getLocal().getBasePath())).filter(FileUtil::isDirectory) - .map(dir -> new Bucket(dir.getName())).collect(Collectors.toList()); + return Arrays.stream(FileUtil.ls(properties.getLocal().getBasePath())) + .filter(FileUtil::isDirectory) + .map(dir -> new Bucket(dir.getName())) + .collect(Collectors.toList()); } /** diff --git a/pigx-common/pigx-common-oss/src/main/java/com/pig4cloud/pigx/common/file/oss/service/OssTemplate.java b/pigx-common/pigx-common-oss/src/main/java/com/pig4cloud/pigx/common/file/oss/service/OssTemplate.java index 44417c8b6..2949ce5d5 100755 --- a/pigx-common/pigx-common-oss/src/main/java/com/pig4cloud/pigx/common/file/oss/service/OssTemplate.java +++ b/pigx-common/pigx-common-oss/src/main/java/com/pig4cloud/pigx/common/file/oss/service/OssTemplate.java @@ -228,9 +228,13 @@ public class OssTemplate implements InitializingBean, FileTemplate { AWSCredentials awsCredentials = new BasicAWSCredentials(properties.getOss().getAccessKey(), properties.getOss().getSecretKey()); AWSCredentialsProvider awsCredentialsProvider = new AWSStaticCredentialsProvider(awsCredentials); - this.amazonS3 = AmazonS3Client.builder().withEndpointConfiguration(endpointConfiguration) - .withClientConfiguration(clientConfiguration).withCredentials(awsCredentialsProvider) - .disableChunkedEncoding().withPathStyleAccessEnabled(properties.getOss().getPathStyleAccess()).build(); + this.amazonS3 = AmazonS3Client.builder() + .withEndpointConfiguration(endpointConfiguration) + .withClientConfiguration(clientConfiguration) + .withCredentials(awsCredentialsProvider) + .disableChunkedEncoding() + .withPathStyleAccessEnabled(properties.getOss().getPathStyleAccess()) + .build(); } } diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PermissionService.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PermissionService.java index 3dee9caa3..a9cc53631 100644 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PermissionService.java +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PermissionService.java @@ -46,8 +46,10 @@ public class PermissionService { return false; } Collection authorities = authentication.getAuthorities(); - return authorities.stream().map(GrantedAuthority::getAuthority).filter(StringUtils::hasText) - .anyMatch(x -> PatternMatchUtils.simpleMatch(permissions, x)); + return authorities.stream() + .map(GrantedAuthority::getAuthority) + .filter(StringUtils::hasText) + .anyMatch(x -> PatternMatchUtils.simpleMatch(permissions, x)); } } diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PermitAllUrlProperties.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PermitAllUrlProperties.java index 32b44a7be..81c8398cc 100755 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PermitAllUrlProperties.java +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PermitAllUrlProperties.java @@ -61,13 +61,17 @@ public class PermitAllUrlProperties implements InitializingBean { // 获取方法上边的注解 替代path variable 为 * Inner method = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), Inner.class); - Optional.ofNullable(method).ifPresent(inner -> Objects.requireNonNull(info.getPathPatternsCondition()) - .getPatternValues().forEach(url -> ignoreUrls.add(ReUtil.replaceAll(url, PATTERN, "*")))); + Optional.ofNullable(method) + .ifPresent(inner -> Objects.requireNonNull(info.getPathPatternsCondition()) + .getPatternValues() + .forEach(url -> ignoreUrls.add(ReUtil.replaceAll(url, PATTERN, "*")))); // 获取类上边的注解, 替代path variable 为 * Inner controller = AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), Inner.class); - Optional.ofNullable(controller).ifPresent(inner -> Objects.requireNonNull(info.getPathPatternsCondition()) - .getPatternValues().forEach(url -> ignoreUrls.add(ReUtil.replaceAll(url, PATTERN, "*")))); + Optional.ofNullable(controller) + .ifPresent(inner -> Objects.requireNonNull(info.getPathPatternsCondition()) + .getPatternValues() + .forEach(url -> ignoreUrls.add(ReUtil.replaceAll(url, PATTERN, "*")))); }); } diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxBearerTokenExtractor.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxBearerTokenExtractor.java index 15931bb6e..0b20244c2 100644 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxBearerTokenExtractor.java +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxBearerTokenExtractor.java @@ -16,6 +16,7 @@ package com.pig4cloud.pigx.common.security.component; +import jakarta.servlet.http.HttpServletRequest; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; @@ -26,7 +27,6 @@ import org.springframework.util.AntPathMatcher; import org.springframework.util.PathMatcher; import org.springframework.util.StringUtils; -import jakarta.servlet.http.HttpServletRequest; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -70,7 +70,7 @@ public class PigxBearerTokenExtractor implements BearerTokenResolver { if (authorizationHeaderToken != null) { if (parameterToken != null) { final BearerTokenError error = BearerTokenErrors - .invalidRequest("Found multiple bearer tokens in the request"); + .invalidRequest("Found multiple bearer tokens in the request"); throw new OAuth2AuthenticationException(error); } return authorizationHeaderToken; diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxCustomOpaqueTokenIntrospector.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxCustomOpaqueTokenIntrospector.java index 45396260c..f3c660d8c 100644 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxCustomOpaqueTokenIntrospector.java +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxCustomOpaqueTokenIntrospector.java @@ -49,12 +49,13 @@ public class PigxCustomOpaqueTokenIntrospector implements OpaqueTokenIntrospecto } Map userDetailsServiceMap = SpringContextHolder - .getBeansOfType(PigxUserDetailsService.class); + .getBeansOfType(PigxUserDetailsService.class); - Optional optional = userDetailsServiceMap.values().stream() - .filter(service -> service.support(Objects.requireNonNull(oldAuthorization).getRegisteredClientId(), - oldAuthorization.getAuthorizationGrantType().getValue())) - .max(Comparator.comparingInt(Ordered::getOrder)); + Optional optional = userDetailsServiceMap.values() + .stream() + .filter(service -> service.support(Objects.requireNonNull(oldAuthorization).getRegisteredClientId(), + oldAuthorization.getAuthorizationGrantType().getValue())) + .max(Comparator.comparingInt(Ordered::getOrder)); UserDetails userDetails = null; try { @@ -73,8 +74,9 @@ public class PigxCustomOpaqueTokenIntrospector implements OpaqueTokenIntrospecto // 注入客户端信息,方便上下文中获取 PigxUser pigxUser = (PigxUser) userDetails; - Objects.requireNonNull(pigxUser).getAttributes().put(SecurityConstants.CLIENT_ID, - oldAuthorization.getRegisteredClientId()); + Objects.requireNonNull(pigxUser) + .getAttributes() + .put(SecurityConstants.CLIENT_ID, oldAuthorization.getRegisteredClientId()); return pigxUser; } diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxResourceServerConfiguration.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxResourceServerConfiguration.java index 21afcf56a..e5da1b8ac 100644 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxResourceServerConfiguration.java +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxResourceServerConfiguration.java @@ -16,7 +16,6 @@ package com.pig4cloud.pigx.common.security.component; -import cn.hutool.core.util.ArrayUtil; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Bean; @@ -29,6 +28,7 @@ import org.springframework.security.config.annotation.web.configurers.AbstractHt import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer; import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector; import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; /** * @author lengleng @@ -53,9 +53,13 @@ public class PigxResourceServerConfiguration { @Bean @Order(Ordered.HIGHEST_PRECEDENCE) SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + AntPathRequestMatcher[] requestMatchers = permitAllUrl.getIgnoreUrls() + .stream() + .map(AntPathRequestMatcher::new) + .toList() + .toArray(new AntPathRequestMatcher[] {}); - http.authorizeHttpRequests(authorizeRequests -> authorizeRequests - .requestMatchers(ArrayUtil.toArray(permitAllUrl.getIgnoreUrls(), String.class)) + http.authorizeHttpRequests(authorizeRequests -> authorizeRequests.requestMatchers(requestMatchers) .permitAll() .anyRequest() .authenticated()) diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxRedisOAuth2AuthorizationConsentService.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxRedisOAuth2AuthorizationConsentService.java index 377e95114..9af1825f5 100644 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxRedisOAuth2AuthorizationConsentService.java +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxRedisOAuth2AuthorizationConsentService.java @@ -19,8 +19,8 @@ public class PigxRedisOAuth2AuthorizationConsentService implements OAuth2Authori public void save(OAuth2AuthorizationConsent authorizationConsent) { Assert.notNull(authorizationConsent, "authorizationConsent cannot be null"); - redisTemplate.opsForValue().set(buildKey(authorizationConsent), authorizationConsent, TIMEOUT, - TimeUnit.MINUTES); + redisTemplate.opsForValue() + .set(buildKey(authorizationConsent), authorizationConsent, TIMEOUT, TimeUnit.MINUTES); } @@ -35,7 +35,7 @@ public class PigxRedisOAuth2AuthorizationConsentService implements OAuth2Authori Assert.hasText(registeredClientId, "registeredClientId cannot be empty"); Assert.hasText(principalName, "principalName cannot be empty"); return (OAuth2AuthorizationConsent) redisTemplate.opsForValue() - .get(buildKey(registeredClientId, principalName)); + .get(buildKey(registeredClientId, principalName)); } private static String buildKey(String registeredClientId, String principalName) { diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxRedisOAuth2AuthorizationService.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxRedisOAuth2AuthorizationService.java index 266108b5a..e67997c0b 100644 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxRedisOAuth2AuthorizationService.java +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxRedisOAuth2AuthorizationService.java @@ -46,35 +46,38 @@ public class PigxRedisOAuth2AuthorizationService implements OAuth2AuthorizationS if (isState(authorization)) { String token = authorization.getAttribute("state"); redisTemplate.setValueSerializer(RedisSerializer.java()); - redisTemplate.opsForValue().set(buildKey(OAuth2ParameterNames.STATE, token), authorization, TIMEOUT, - TimeUnit.MINUTES); + redisTemplate.opsForValue() + .set(buildKey(OAuth2ParameterNames.STATE, token), authorization, TIMEOUT, TimeUnit.MINUTES); } if (isCode(authorization)) { OAuth2Authorization.Token authorizationCode = authorization - .getToken(OAuth2AuthorizationCode.class); + .getToken(OAuth2AuthorizationCode.class); OAuth2AuthorizationCode authorizationCodeToken = authorizationCode.getToken(); long between = ChronoUnit.MINUTES.between(authorizationCodeToken.getIssuedAt(), authorizationCodeToken.getExpiresAt()); redisTemplate.setValueSerializer(RedisSerializer.java()); - redisTemplate.opsForValue().set(buildKey(OAuth2ParameterNames.CODE, authorizationCodeToken.getTokenValue()), - authorization, between, TimeUnit.MINUTES); + redisTemplate.opsForValue() + .set(buildKey(OAuth2ParameterNames.CODE, authorizationCodeToken.getTokenValue()), authorization, + between, TimeUnit.MINUTES); } if (isRefreshToken(authorization)) { OAuth2RefreshToken refreshToken = authorization.getRefreshToken().getToken(); long between = ChronoUnit.SECONDS.between(refreshToken.getIssuedAt(), refreshToken.getExpiresAt()); redisTemplate.setValueSerializer(RedisSerializer.java()); - redisTemplate.opsForValue().set(buildKey(OAuth2ParameterNames.REFRESH_TOKEN, refreshToken.getTokenValue()), - authorization, between, TimeUnit.SECONDS); + redisTemplate.opsForValue() + .set(buildKey(OAuth2ParameterNames.REFRESH_TOKEN, refreshToken.getTokenValue()), authorization, between, + TimeUnit.SECONDS); } if (isAccessToken(authorization)) { OAuth2AccessToken accessToken = authorization.getAccessToken().getToken(); long between = ChronoUnit.SECONDS.between(accessToken.getIssuedAt(), accessToken.getExpiresAt()); redisTemplate.setValueSerializer(RedisSerializer.java()); - redisTemplate.opsForValue().set(buildKey(OAuth2ParameterNames.ACCESS_TOKEN, accessToken.getTokenValue()), - authorization, between, TimeUnit.SECONDS); + redisTemplate.opsForValue() + .set(buildKey(OAuth2ParameterNames.ACCESS_TOKEN, accessToken.getTokenValue()), authorization, between, + TimeUnit.SECONDS); // 扩展记录 access-token 、username 的关系 1::token::username::admin::xxx String tokenUsername = String.format("%s::%s::%s::%s::%s", tenantKeyStrResolver.key(), AUTHORIZATION, @@ -95,7 +98,7 @@ public class PigxRedisOAuth2AuthorizationService implements OAuth2AuthorizationS if (isCode(authorization)) { OAuth2Authorization.Token authorizationCode = authorization - .getToken(OAuth2AuthorizationCode.class); + .getToken(OAuth2AuthorizationCode.class); OAuth2AuthorizationCode authorizationCodeToken = authorizationCode.getToken(); keys.add(buildKey(OAuth2ParameterNames.CODE, authorizationCodeToken.getTokenValue())); } @@ -143,7 +146,7 @@ public class PigxRedisOAuth2AuthorizationService implements OAuth2AuthorizationS private static boolean isCode(OAuth2Authorization authorization) { OAuth2Authorization.Token authorizationCode = authorization - .getToken(OAuth2AuthorizationCode.class); + .getToken(OAuth2AuthorizationCode.class); return Objects.nonNull(authorizationCode); } diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxRemoteRegisteredClientRepository.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxRemoteRegisteredClientRepository.java index 275a2ecab..275e1aa60 100644 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxRemoteRegisteredClientRepository.java +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxRemoteRegisteredClientRepository.java @@ -88,46 +88,53 @@ public class PigxRemoteRegisteredClientRepository implements RegisteredClientRep public RegisteredClient findByClientId(String clientId) { SysOauthClientDetails clientDetails = RetOps - .of(clientDetailsService.getClientDetailsById(clientId, SecurityConstants.FROM_IN)).getData() - .orElseThrow(() -> new OAuth2AuthorizationCodeRequestAuthenticationException( - new OAuth2Error("客户端查询异常,请检查数据库链接"), null)); + .of(clientDetailsService.getClientDetailsById(clientId, SecurityConstants.FROM_IN)) + .getData() + .orElseThrow(() -> new OAuth2AuthorizationCodeRequestAuthenticationException( + new OAuth2Error("客户端查询异常,请检查数据库链接"), null)); RegisteredClient.Builder builder = RegisteredClient.withId(clientDetails.getClientId()) - .clientId(clientDetails.getClientId()) - .clientSecret(SecurityConstants.NOOP + clientDetails.getClientSecret()) - .clientAuthenticationMethods(clientAuthenticationMethods -> { - clientAuthenticationMethods.add(ClientAuthenticationMethod.CLIENT_SECRET_BASIC); - clientAuthenticationMethods.add(ClientAuthenticationMethod.CLIENT_SECRET_POST); - }); + .clientId(clientDetails.getClientId()) + .clientSecret(SecurityConstants.NOOP + clientDetails.getClientSecret()) + .clientAuthenticationMethods(clientAuthenticationMethods -> { + clientAuthenticationMethods.add(ClientAuthenticationMethod.CLIENT_SECRET_BASIC); + clientAuthenticationMethods.add(ClientAuthenticationMethod.CLIENT_SECRET_POST); + }); // 授权模式 Arrays.stream(clientDetails.getAuthorizedGrantTypes()) - .forEach(grant -> builder.authorizationGrantType(new AuthorizationGrantType(grant))); + .forEach(grant -> builder.authorizationGrantType(new AuthorizationGrantType(grant))); // 回调地址 - Optional.ofNullable(clientDetails.getWebServerRedirectUri()).ifPresent(redirectUri -> Arrays - .stream(redirectUri.split(StrUtil.COMMA)).filter(StrUtil::isNotBlank).forEach(builder::redirectUri)); + Optional.ofNullable(clientDetails.getWebServerRedirectUri()) + .ifPresent(redirectUri -> Arrays.stream(redirectUri.split(StrUtil.COMMA)) + .filter(StrUtil::isNotBlank) + .forEach(builder::redirectUri)); // scope - Optional.ofNullable(clientDetails.getScope()).ifPresent( - scope -> Arrays.stream(scope.split(StrUtil.COMMA)).filter(StrUtil::isNotBlank).forEach(builder::scope)); + Optional.ofNullable(clientDetails.getScope()) + .ifPresent(scope -> Arrays.stream(scope.split(StrUtil.COMMA)) + .filter(StrUtil::isNotBlank) + .forEach(builder::scope)); // 注入扩展配置 Optional.ofNullable(clientDetails.getAdditionalInformation()).ifPresent(ext -> { Map map = JSONUtil.parseObj(ext).toBean(Map.class); - builder.clientSettings(ClientSettings.withSettings(map).requireProofKey(false) - .requireAuthorizationConsent(!BooleanUtil.toBoolean(clientDetails.getAutoapprove())).build()); + builder.clientSettings(ClientSettings.withSettings(map) + .requireProofKey(false) + .requireAuthorizationConsent(!BooleanUtil.toBoolean(clientDetails.getAutoapprove())) + .build()); }); return builder - .tokenSettings(TokenSettings.builder().accessTokenFormat(OAuth2TokenFormat.REFERENCE) - .accessTokenTimeToLive(Duration.ofSeconds(Optional - .ofNullable(clientDetails.getAccessTokenValidity()).orElse(accessTokenValiditySeconds))) - .refreshTokenTimeToLive( - Duration.ofSeconds(Optional.ofNullable(clientDetails.getRefreshTokenValidity()) - .orElse(refreshTokenValiditySeconds))) - .build()) + .tokenSettings(TokenSettings.builder() + .accessTokenFormat(OAuth2TokenFormat.REFERENCE) + .accessTokenTimeToLive(Duration.ofSeconds( + Optional.ofNullable(clientDetails.getAccessTokenValidity()).orElse(accessTokenValiditySeconds))) + .refreshTokenTimeToLive(Duration.ofSeconds(Optional.ofNullable(clientDetails.getRefreshTokenValidity()) + .orElse(refreshTokenValiditySeconds))) + .build()) - .build(); + .build(); } diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxTocDefaultUserDetailsServiceImpl.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxTocDefaultUserDetailsServiceImpl.java index f240cec9d..68d0f0380 100755 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxTocDefaultUserDetailsServiceImpl.java +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxTocDefaultUserDetailsServiceImpl.java @@ -104,7 +104,7 @@ public class PigxTocDefaultUserDetailsServiceImpl implements PigxUserDetailsServ } Collection authorities = AuthorityUtils - .createAuthorityList(dbAuthsSet.toArray(new String[0])); + .createAuthorityList(dbAuthsSet.toArray(new String[0])); AppUser user = info.getAppUser(); // 构造security用户 diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxTocMobileUserDetailsServiceImpl.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxTocMobileUserDetailsServiceImpl.java index 1d6c074ae..259be18be 100644 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxTocMobileUserDetailsServiceImpl.java +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxTocMobileUserDetailsServiceImpl.java @@ -88,7 +88,7 @@ public class PigxTocMobileUserDetailsServiceImpl implements PigxUserDetailsServi } Collection authorities = AuthorityUtils - .createAuthorityList(dbAuthsSet.toArray(new String[0])); + .createAuthorityList(dbAuthsSet.toArray(new String[0])); AppUser user = info.getAppUser(); // 构造security用户 diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxUserDetailsService.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxUserDetailsService.java index 3c0100f65..486cced57 100644 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxUserDetailsService.java +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/service/PigxUserDetailsService.java @@ -90,7 +90,7 @@ public interface PigxUserDetailsService extends UserDetailsService, Ordered { } Collection authorities = AuthorityUtils - .createAuthorityList(dbAuthsSet.toArray(new String[0])); + .createAuthorityList(dbAuthsSet.toArray(new String[0])); SysUser user = info.getSysUser(); // 构造security用户 diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/util/OAuth2EndpointUtils.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/util/OAuth2EndpointUtils.java index d8d53e81a..a8a0f0e6d 100644 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/util/OAuth2EndpointUtils.java +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/util/OAuth2EndpointUtils.java @@ -1,6 +1,7 @@ package com.pig4cloud.pigx.common.security.util; import cn.hutool.core.map.MapUtil; +import jakarta.servlet.http.HttpServletRequest; import lombok.experimental.UtilityClass; import org.springframework.security.oauth2.core.*; import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse; @@ -10,7 +11,6 @@ import org.springframework.security.oauth2.server.authorization.OAuth2Authorizat import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; -import jakarta.servlet.http.HttpServletRequest; import java.io.IOException; import java.time.temporal.ChronoUnit; import java.util.Map; @@ -29,15 +29,15 @@ public class OAuth2EndpointUtils { MultiValueMap parameters = new LinkedMultiValueMap<>(parameterMap.size()); parameterMap.forEach((key, values) -> { for (String value : values) { - parameters.add(key, value); - } + parameters.add(key, value); + } }); return parameters; } public boolean matchesPkceTokenRequest(HttpServletRequest request) { return AuthorizationGrantType.AUTHORIZATION_CODE.getValue() - .equals(request.getParameter(OAuth2ParameterNames.GRANT_TYPE)) + .equals(request.getParameter(OAuth2ParameterNames.GRANT_TYPE)) && request.getParameter(OAuth2ParameterNames.CODE) != null && request.getParameter(PkceParameterNames.CODE_VERIFIER) != null; } @@ -61,7 +61,8 @@ public class OAuth2EndpointUtils { OAuth2RefreshToken refreshToken = authentication.getRefreshToken().getToken(); OAuth2AccessTokenResponse.Builder builder = OAuth2AccessTokenResponse.withToken(accessToken.getTokenValue()) - .tokenType(accessToken.getTokenType()).scopes(accessToken.getScopes()); + .tokenType(accessToken.getTokenType()) + .scopes(accessToken.getScopes()); if (accessToken.getIssuedAt() != null && accessToken.getExpiresAt() != null) { builder.expiresIn(ChronoUnit.SECONDS.between(accessToken.getIssuedAt(), accessToken.getExpiresAt())); } diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/util/SecurityUtils.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/util/SecurityUtils.java index 02188a3ad..abe04b869 100644 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/util/SecurityUtils.java +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/util/SecurityUtils.java @@ -75,11 +75,12 @@ public class SecurityUtils { Collection authorities = authentication.getAuthorities(); List roleIds = new ArrayList<>(); - authorities.stream().filter(granted -> StrUtil.startWith(granted.getAuthority(), SecurityConstants.ROLE)) - .forEach(granted -> { - String id = StrUtil.removePrefix(granted.getAuthority(), SecurityConstants.ROLE); - roleIds.add(Long.parseLong(id)); - }); + authorities.stream() + .filter(granted -> StrUtil.startWith(granted.getAuthority(), SecurityConstants.ROLE)) + .forEach(granted -> { + String id = StrUtil.removePrefix(granted.getAuthority(), SecurityConstants.ROLE); + roleIds.add(Long.parseLong(id)); + }); return roleIds; } diff --git a/pigx-common/pigx-common-sentinel/src/main/java/com/pig4cloud/pigx/common/sentinel/feign/PigxSentinelInvocationHandler.java b/pigx-common/pigx-common-sentinel/src/main/java/com/pig4cloud/pigx/common/sentinel/feign/PigxSentinelInvocationHandler.java index bbebf2727..8926d35ec 100644 --- a/pigx-common/pigx-common-sentinel/src/main/java/com/pig4cloud/pigx/common/sentinel/feign/PigxSentinelInvocationHandler.java +++ b/pigx-common/pigx-common-sentinel/src/main/java/com/pig4cloud/pigx/common/sentinel/feign/PigxSentinelInvocationHandler.java @@ -84,7 +84,7 @@ public class PigxSentinelInvocationHandler implements InvocationHandler { if (target instanceof Target.HardCodedTarget) { Target.HardCodedTarget hardCodedTarget = (Target.HardCodedTarget) target; MethodMetadata methodMetadata = SentinelContractHolder.METADATA_MAP - .get(hardCodedTarget.type().getName() + Feign.configKey(hardCodedTarget.type(), method)); + .get(hardCodedTarget.type().getName() + Feign.configKey(hardCodedTarget.type(), method)); // resource default is HttpMethod:protocol://url if (methodMetadata == null) { result = methodHandler.invoke(args); @@ -105,8 +105,8 @@ public class PigxSentinelInvocationHandler implements InvocationHandler { } if (fallbackFactory != null) { try { - Object fallbackResult = fallbackMethodMap.get(method).invoke(fallbackFactory.create(ex), - args); + Object fallbackResult = fallbackMethodMap.get(method) + .invoke(fallbackFactory.create(ex), args); return fallbackResult; } catch (IllegalAccessException e) { diff --git a/pigx-common/pigx-common-sequence/src/main/java/com/pig4cloud/pigx/common/sequence/SequenceAutoConfiguration.java b/pigx-common/pigx-common-sequence/src/main/java/com/pig4cloud/pigx/common/sequence/SequenceAutoConfiguration.java index 79656edbd..900cefc8e 100644 --- a/pigx-common/pigx-common-sequence/src/main/java/com/pig4cloud/pigx/common/sequence/SequenceAutoConfiguration.java +++ b/pigx-common/pigx-common-sequence/src/main/java/com/pig4cloud/pigx/common/sequence/SequenceAutoConfiguration.java @@ -43,8 +43,10 @@ public class SequenceAutoConfiguration { @Bean @ConditionalOnBean(SequenceSnowflakeProperties.class) public Sequence snowflakeSequence(SequenceSnowflakeProperties properties) { - return SnowflakeSeqBuilder.create().datacenterId(properties.getDatacenterId()) - .workerId(properties.getWorkerId()).build(); + return SnowflakeSeqBuilder.create() + .datacenterId(properties.getDatacenterId()) + .workerId(properties.getWorkerId()) + .build(); } } \ No newline at end of file diff --git a/pigx-common/pigx-common-sequence/src/main/java/com/pig4cloud/pigx/common/sequence/range/impl/db/BaseDbHelper.java b/pigx-common/pigx-common-sequence/src/main/java/com/pig4cloud/pigx/common/sequence/range/impl/db/BaseDbHelper.java index 3dbe3e461..bc1248069 100755 --- a/pigx-common/pigx-common-sequence/src/main/java/com/pig4cloud/pigx/common/sequence/range/impl/db/BaseDbHelper.java +++ b/pigx-common/pigx-common-sequence/src/main/java/com/pig4cloud/pigx/common/sequence/range/impl/db/BaseDbHelper.java @@ -17,7 +17,7 @@ import java.sql.*; abstract class BaseDbHelper { private static final SqlProviderFactory SQL_PROVIDER_FACTORY = SpringContextHolder - .getBean(SqlProviderFactory.class); + .getBean(SqlProviderFactory.class); private static final long DELTA = 100000000L; @@ -186,7 +186,7 @@ abstract class BaseDbHelper { conn = dataSource.getConnection(); stmt = conn.createStatement(); ResultSet resultSet = stmt - .executeQuery(SQL_PROVIDER_FACTORY.getExistTableSql().replace("#tableName", tableName)); + .executeQuery(SQL_PROVIDER_FACTORY.getExistTableSql().replace("#tableName", tableName)); if (!resultSet.next()) { return false; diff --git a/pigx-common/pigx-common-swagger/src/main/java/com/pig4cloud/pigx/common/swagger/config/OpenAPIDefinitionImportSelector.java b/pigx-common/pigx-common-swagger/src/main/java/com/pig4cloud/pigx/common/swagger/config/OpenAPIDefinitionImportSelector.java index 3df05b3ad..a84f8c790 100644 --- a/pigx-common/pigx-common-swagger/src/main/java/com/pig4cloud/pigx/common/swagger/config/OpenAPIDefinitionImportSelector.java +++ b/pigx-common/pigx-common-swagger/src/main/java/com/pig4cloud/pigx/common/swagger/config/OpenAPIDefinitionImportSelector.java @@ -40,7 +40,7 @@ public class OpenAPIDefinitionImportSelector implements ImportBeanDefinitionRegi } BeanDefinitionBuilder openAPIMetadata = BeanDefinitionBuilder - .genericBeanDefinition(OpenAPIMetadataConfiguration.class); + .genericBeanDefinition(OpenAPIMetadataConfiguration.class); openAPIMetadata.addPropertyValue("path", value); registry.registerBeanDefinition("openAPIMetadata", openAPIMetadata.getBeanDefinition()); } diff --git a/pigx-common/pigx-common-websocket/src/main/java/com/pig4cloud/pigx/common/websocket/config/WebSocketAutoConfiguration.java b/pigx-common/pigx-common-websocket/src/main/java/com/pig4cloud/pigx/common/websocket/config/WebSocketAutoConfiguration.java index 34a8e9369..3dd1b3f91 100644 --- a/pigx-common/pigx-common-websocket/src/main/java/com/pig4cloud/pigx/common/websocket/config/WebSocketAutoConfiguration.java +++ b/pigx-common/pigx-common-websocket/src/main/java/com/pig4cloud/pigx/common/websocket/config/WebSocketAutoConfiguration.java @@ -2,6 +2,7 @@ package com.pig4cloud.pigx.common.websocket.config; import com.pig4cloud.pigx.common.websocket.handler.JsonMessageHandler; import com.pig4cloud.pigx.common.websocket.holder.JsonMessageHandlerHolder; +import jakarta.annotation.PostConstruct; import lombok.RequiredArgsConstructor; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; @@ -11,7 +12,6 @@ import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.server.HandshakeInterceptor; -import jakarta.annotation.PostConstruct; import java.util.List; /** @@ -33,8 +33,8 @@ public class WebSocketAutoConfiguration { public WebSocketConfigurer webSocketConfigurer(List handshakeInterceptor, WebSocketHandler webSocketHandler) { return registry -> registry.addHandler(webSocketHandler, webSocketProperties.getPath()) - .setAllowedOrigins(webSocketProperties.getAllowOrigins()) - .addInterceptors(handshakeInterceptor.toArray(new HandshakeInterceptor[0])); + .setAllowedOrigins(webSocketProperties.getAllowOrigins()) + .addInterceptors(handshakeInterceptor.toArray(new HandshakeInterceptor[0])); } /** diff --git a/pigx-common/pigx-common-xss/src/main/java/com/pig4cloud/pigx/common/xss/PigxXssAutoConfiguration.java b/pigx-common/pigx-common-xss/src/main/java/com/pig4cloud/pigx/common/xss/PigxXssAutoConfiguration.java index eeaebfee0..1f8f0f2ba 100644 --- a/pigx-common/pigx-common-xss/src/main/java/com/pig4cloud/pigx/common/xss/PigxXssAutoConfiguration.java +++ b/pigx-common/pigx-common-xss/src/main/java/com/pig4cloud/pigx/common/xss/PigxXssAutoConfiguration.java @@ -70,8 +70,10 @@ public class PigxXssAutoConfiguration implements WebMvcConfigurer { patterns.add("/**"); } XssCleanInterceptor interceptor = new XssCleanInterceptor(xssProperties); - registry.addInterceptor(interceptor).addPathPatterns(patterns) - .excludePathPatterns(xssProperties.getPathExcludePatterns()).order(Ordered.LOWEST_PRECEDENCE); + registry.addInterceptor(interceptor) + .addPathPatterns(patterns) + .excludePathPatterns(xssProperties.getPathExcludePatterns()) + .order(Ordered.LOWEST_PRECEDENCE); } } diff --git a/pigx-common/pigx-common-xss/src/main/java/com/pig4cloud/pigx/common/xss/core/DefaultXssCleaner.java b/pigx-common/pigx-common-xss/src/main/java/com/pig4cloud/pigx/common/xss/core/DefaultXssCleaner.java index 9f8fb0a48..23d003986 100644 --- a/pigx-common/pigx-common-xss/src/main/java/com/pig4cloud/pigx/common/xss/core/DefaultXssCleaner.java +++ b/pigx-common/pigx-common-xss/src/main/java/com/pig4cloud/pigx/common/xss/core/DefaultXssCleaner.java @@ -51,10 +51,10 @@ public class DefaultXssCleaner implements XssCleaner { else { // jsoup html 清理 Document.OutputSettings outputSettings = new Document.OutputSettings() - // 2. 转义,没找到关闭的方法,目前这个规则最少 - .escapeMode(Entities.EscapeMode.xhtml) - // 3. 保留换行 - .prettyPrint(properties.isPrettyPrint()); + // 2. 转义,没找到关闭的方法,目前这个规则最少 + .escapeMode(Entities.EscapeMode.xhtml) + // 3. 保留换行 + .prettyPrint(properties.isPrettyPrint()); Document dirty = Jsoup.parseBodyFragment(bodyHtml, ""); Cleaner cleaner = new Cleaner(XssUtil.WHITE_LIST); Document clean = cleaner.clean(dirty); diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-api/pom.xml b/pigx-flow/pigx-flow-engine/pigx-flow-engine-api/pom.xml new file mode 100644 index 000000000..ee18eaff8 --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-api/pom.xml @@ -0,0 +1,42 @@ + + + 4.0.0 + + com.pig4cloud + pigx-flow-engine + 5.2.0-snapshot + + + pigx-flow-engine-api + + + + + com.pig4cloud + pigx-common-core + + + com.alibaba.fastjson2 + fastjson2 + 2.0.28 + + + + com.baomidou + mybatis-plus-extension + + + + com.pig4cloud + pigx-common-feign + + + + com.pig4cloud + pigx-common-excel + + + diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-api/src/main/java/com/pig4cloud/pigx/flow/engine/api/feign/packge-info.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-api/src/main/java/com/pig4cloud/pigx/flow/engine/api/feign/packge-info.java new file mode 100644 index 000000000..b3dce91f5 --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-api/src/main/java/com/pig4cloud/pigx/flow/engine/api/feign/packge-info.java @@ -0,0 +1,6 @@ +/* + @author pigx archetype + *

+ * feign client 存放目录,注意 @EnablePigxFeignClients 的扫描范围 + */ +package com.pig4cloud.pigx.flow.engine.api.feign; \ No newline at end of file diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-api/src/main/java/com/pig4cloud/pigx/flow/engine/constant/packge-info.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-api/src/main/java/com/pig4cloud/pigx/flow/engine/constant/packge-info.java new file mode 100644 index 000000000..99b19b1da --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-api/src/main/java/com/pig4cloud/pigx/flow/engine/constant/packge-info.java @@ -0,0 +1,6 @@ +/* + * @author pigx archetype + *

+ * 常量和枚举定义 + */ +package com.pig4cloud.pigx.flow.engine.constant; \ No newline at end of file diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-api/src/main/java/com/pig4cloud/pigx/flow/engine/dto/packge-info.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-api/src/main/java/com/pig4cloud/pigx/flow/engine/dto/packge-info.java new file mode 100644 index 000000000..6d96d5cdd --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-api/src/main/java/com/pig4cloud/pigx/flow/engine/dto/packge-info.java @@ -0,0 +1,6 @@ +/* + * @author pigx archetype + *

+ * DTO 存放目录 + */ +package com.pig4cloud.pigx.flow.engine.dto; \ No newline at end of file diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-api/src/main/java/com/pig4cloud/pigx/flow/engine/entity/packge-info.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-api/src/main/java/com/pig4cloud/pigx/flow/engine/entity/packge-info.java new file mode 100644 index 000000000..f841cdff5 --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-api/src/main/java/com/pig4cloud/pigx/flow/engine/entity/packge-info.java @@ -0,0 +1,6 @@ +/* + * @author pigx archetype + *

+ * 实体 存放目录 + */ +package com.pig4cloud.pigx.flow.engine.entity; \ No newline at end of file diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/pom.xml b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/pom.xml new file mode 100644 index 000000000..2fcf12ba5 --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/pom.xml @@ -0,0 +1,134 @@ + + + 4.0.0 + + com.pig4cloud + pigx-flow-engine + 5.2.0-snapshot + + + pigx-flow-engine-biz + + + + + org.flowable + flowable-bpmn-layout + ${flowable.version} + + + org.flowable + flowable-spring-boot-starter-process + ${flowable.version} + + + + com.pig4cloud + pigx-flow-task-api + + + + com.googlecode.aviator + aviator + + + + org.springframework.boot + spring-boot-starter-undertow + + + + org.springframework.boot + spring-boot-starter-web + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-config + + + + com.pig4cloud + pigx-common-data + + + + com.pig4cloud + pigx-common-security + + + + com.pig4cloud + pigx-common-xss + + + + com.pig4cloud + pigx-common-sentinel + + + + com.pig4cloud + pigx-common-feign + + + + com.pig4cloud + pigx-flow-engine-api + + + + com.pig4cloud + pigx-common-log + + + + com.baomidou + mybatis-plus-boot-starter + + + + com.alibaba + druid-spring-boot-3-starter + + + + com.mysql + mysql-connector-j + + + + com.pig4cloud + pigx-common-swagger + + + cn.hutool + hutool-cache + + + + org.springframework.boot + spring-boot-starter-test + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + io.fabric8 + docker-maven-plugin + + + + diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/PigxFlowEngineApplication.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/PigxFlowEngineApplication.java new file mode 100644 index 000000000..fef1590f2 --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/PigxFlowEngineApplication.java @@ -0,0 +1,26 @@ +package com.pig4cloud.pigx.flow.engine; + +import com.pig4cloud.pigx.common.feign.annotation.EnablePigxFeignClients; +import com.pig4cloud.pigx.common.security.annotation.EnablePigxResourceServer; +import com.pig4cloud.pigx.common.swagger.annotation.EnableOpenApi; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; + +/** + * @author pigx archetype + *

+ * 项目启动类 + */ +@EnableOpenApi("engine") +@EnablePigxFeignClients +@EnableDiscoveryClient +@EnablePigxResourceServer +@SpringBootApplication +public class PigxFlowEngineApplication { + + public static void main(String[] args) { + SpringApplication.run(PigxFlowEngineApplication.class, args); + } + +} diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/controller/EngineFlowController.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/controller/EngineFlowController.java new file mode 100644 index 000000000..463a6e59a --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/controller/EngineFlowController.java @@ -0,0 +1,369 @@ +package com.pig4cloud.pigx.flow.engine.controller; + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.RandomUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.engine.utils.ModelUtil; +import com.pig4cloud.pigx.flow.task.dto.*; +import com.pig4cloud.pigx.flow.task.entity.Process; +import com.pig4cloud.pigx.flow.task.utils.NodeUtil; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.flowable.bpmn.BpmnAutoLayout; +import org.flowable.bpmn.converter.BpmnXMLConverter; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.common.engine.impl.identity.Authentication; +import org.flowable.engine.HistoryService; +import org.flowable.engine.RepositoryService; +import org.flowable.engine.RuntimeService; +import org.flowable.engine.TaskService; +import org.flowable.engine.history.HistoricActivityInstance; +import org.flowable.engine.history.HistoricActivityInstanceQuery; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.runtime.Execution; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.image.impl.DefaultProcessDiagramGenerator; +import org.flowable.task.api.TaskQuery; +import org.springframework.web.bind.annotation.*; + +import java.io.InputStream; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 工作流控制器 负责流程模型的创建、启动、审批等功能 + */ +@Slf4j +@RestController +@RequiredArgsConstructor +@RequestMapping("/flow") +public class EngineFlowController { + + private final TaskService taskService; + + private final HistoryService historyService; + + private final RepositoryService repositoryService; + + private final RuntimeService runtimeService; + + private final ObjectMapper objectMapper; + + /** + * 创建流程定义 + * @param map 创建参数 + * @return 流程定义ID + */ + @PostMapping("create") + @SneakyThrows + public R create(@RequestBody Map map) { + + Long userId = MapUtil.getLong(map, "userId"); + + Process process = MapUtil.get(map, "process", Process.class); + + String flowId = "P" + userId + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_MS_PATTERN) + + RandomUtil.randomString(5); + log.info("flowId={}", flowId); + BpmnModel bpmnModel = ModelUtil.buildBpmnModel(objectMapper.readValue(process.getProcess(), Node.class), + process.getName(), flowId); + { + byte[] bpmnBytess = new BpmnXMLConverter().convertToXML(bpmnModel); + String filename = "/tmp/flowable-deployment/" + flowId + ".bpmn20.xml"; + log.debug("部署时的模型文件:{}", filename); + FileUtil.writeBytes(bpmnBytess, filename); + } + repositoryService.createDeployment().addBpmnModel(StrUtil.format("{}.bpmn20.xml", "test1"), bpmnModel).deploy(); + + return R.ok(flowId); + } + + /** + * 启动流程实例 + * @param processInstanceParamDto 启动参数 + * @return 流程实例ID + */ + @PostMapping("/start") + public R start(@RequestBody ProcessInstanceParamDto processInstanceParamDto) { + Authentication.setAuthenticatedUserId(processInstanceParamDto.getStartUserId()); + ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processInstanceParamDto.getFlowId(), + processInstanceParamDto.getParamMap()); + + String processInstanceId = processInstance.getProcessInstanceId(); + return R.ok(processInstanceId); + + } + + @GetMapping("/showImg") + public R showImg(String procInsId) { + + String procDefId; + ProcessInstance processInstance = runtimeService.createProcessInstanceQuery() + .processInstanceId(procInsId) + .singleResult(); + if (processInstance == null) { + HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery() + .processInstanceId(procInsId) + .singleResult(); + procDefId = historicProcessInstance.getProcessDefinitionId(); + + } + else { + procDefId = processInstance.getProcessDefinitionId(); + } + + // 使用流程实例ID,查询正在执行的执行对象表,返回流程实例对象 + BpmnModel bpmnModel = repositoryService.getBpmnModel(procDefId); + + // 创建默认的流程图生成器 + DefaultProcessDiagramGenerator defaultProcessDiagramGenerator = new DefaultProcessDiagramGenerator(); + // 生成图片的类型 + String imageType = "png"; + // 高亮节点集合 + List highLightedActivities = new ArrayList<>(); + // 高亮连线集合 + List highLightedFlows = new ArrayList<>(); + // 查询所有历史节点信息 + List hisActInsList = historyService.createHistoricActivityInstanceQuery() + .processInstanceId(procInsId) + .list(); + + // 遍历 + hisActInsList.forEach(historicActivityInstance -> { + if ("sequenceFlow".equals(historicActivityInstance.getActivityType())) { + // 添加高亮连线 + highLightedFlows.add(historicActivityInstance.getActivityId()); + } + else { + // 添加高亮节点 + highLightedActivities.add(historicActivityInstance.getActivityId()); + } + }); + // 节点字体 + String activityFontName = "宋体"; + // 连线标签字体 + String labelFontName = "微软雅黑"; + // 连线标签字体 + String annotationFontName = "宋体"; + // 类加载器 + ClassLoader customClassLoader = null; + // 比例因子,默认即可 + double scaleFactor = 1.0d; + // 不设置连线标签不会画 + boolean drawSequenceFlowNameWithNoLabelDI = true; + + BpmnAutoLayout bpmnAutoLayout = new BpmnAutoLayout(bpmnModel); + bpmnAutoLayout.setTaskHeight(120); + bpmnAutoLayout.setTaskWidth(120); + bpmnAutoLayout.execute(); + // 生成图片 + InputStream inputStream = defaultProcessDiagramGenerator.generateDiagram(bpmnModel, imageType, + highLightedActivities, highLightedFlows, activityFontName, labelFontName, annotationFontName, null, + scaleFactor, drawSequenceFlowNameWithNoLabelDI); // 获取输入流 + + String content = Base64.encode(inputStream); + return R.ok(content); + } + + /** + * 审批任务 + * @param taskId 任务ID + * @param approved 是否通过 + */ + @PostMapping("/approve") + public void approve(String taskId, boolean approved) { + Map variables = new HashMap<>(); + variables.put("approved", approved); + variables.put("ko", 10); + variables.put("assigneeListSub", CollUtil.newArrayList("aa", "bb")); + taskService.complete(taskId, variables); + + } + + /** + * 停止流程实例 + * @param taskParamDto 参数 + * @return 操作结果 + */ + @PostMapping("stopProcessInstance") + public R stopProcessInstance(@RequestBody TaskParamDto taskParamDto) { + List processInstanceIdList = taskParamDto.getProcessInstanceIdList(); + processInstanceIdList.forEach(processInstanceId -> { + // 查询流程实例 + ProcessInstance processInstance = runtimeService.createProcessInstanceQuery() + .processInstanceId(processInstanceId) + .singleResult(); + if (Optional.ofNullable(processInstance).isPresent()) { + // 查询执行实例 + List executionIds = runtimeService.createExecutionQuery() + .parentId(processInstanceId) + .list() + .stream() + .map(Execution::getId) + .collect(Collectors.toList()); + // 更改活动状态为结束 + runtimeService.createChangeActivityStateBuilder() + .moveExecutionsToSingleActivityId(executionIds, "end") + .changeState(); + } + }); + return R.ok(); + } + + /** + * 查询用户已办任务 + * @param taskQueryParamDto 查询参数 + * @return 分页任务信息 + */ + @PostMapping("/queryCompletedTask") + public R queryCompletedTask(@RequestBody TaskQueryParamDto taskQueryParamDto) { + HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService + .createHistoricActivityInstanceQuery(); + HistoricActivityInstanceQuery activityInstanceQuery = historicActivityInstanceQuery + .taskAssignee(taskQueryParamDto.getAssign()) + .finished() + .orderByHistoricActivityInstanceEndTime() + .desc(); + + if (ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime())) { + ZoneId zoneId = ZoneId.systemDefault(); + ZonedDateTime zonedBeforeDateTime = taskQueryParamDto.getTaskTime()[0].atZone(zoneId); + ZonedDateTime zonedAfterDateTime = taskQueryParamDto.getTaskTime()[1].atZone(zoneId); + Date beforeDate = Date.from(zonedBeforeDateTime.toInstant()); + Date afterDate = Date.from(zonedAfterDateTime.toInstant()); + activityInstanceQuery.finishedBefore(afterDate).finishedAfter(beforeDate); + } + + List list = activityInstanceQuery.listPage( + (taskQueryParamDto.getPageNum() - 1) * taskQueryParamDto.getPageSize(), + taskQueryParamDto.getPageSize()); + + long count = activityInstanceQuery.count(); + List taskDtoList = new ArrayList<>(); + + for (HistoricActivityInstance historicActivityInstance : list) { + String activityId = historicActivityInstance.getActivityId(); + String activityName = historicActivityInstance.getActivityName(); + String executionId = historicActivityInstance.getExecutionId(); + String taskId = historicActivityInstance.getTaskId(); + Date startTime = historicActivityInstance.getStartTime(); + Date endTime = historicActivityInstance.getEndTime(); + Long durationInMillis = historicActivityInstance.getDurationInMillis(); + String processInstanceId = historicActivityInstance.getProcessInstanceId(); + + String processDefinitionId = historicActivityInstance.getProcessDefinitionId(); + // 流程id + String flowId = NodeUtil.getFlowId(processDefinitionId); + + TaskDto taskDto = new TaskDto(); + taskDto.setFlowId(flowId); + taskDto.setTaskCreateTime(startTime); + taskDto.setTaskEndTime(endTime); + taskDto.setNodeId(activityId); + taskDto.setExecutionId(executionId); + taskDto.setProcessInstanceId(processInstanceId); + taskDto.setDurationInMillis(durationInMillis); + taskDto.setTaskId(taskId); + taskDto.setAssign(historicActivityInstance.getAssignee()); + taskDto.setTaskName(activityName); + + taskDtoList.add(taskDto); + } + + Page pageResultDto = new Page<>(); + pageResultDto.setTotal(count); + pageResultDto.setRecords(taskDtoList); + return R.ok(pageResultDto); + } + + /** + * 查询用户待办任务 + * @param taskQueryParamDto 查询参数 + * @return 分页任务信息 + */ + @PostMapping("/queryAssignTask") + public R queryAssignTask(@RequestBody TaskQueryParamDto taskQueryParamDto) { + + String assign = taskQueryParamDto.getAssign(); + + List taskDtoList = new ArrayList<>(); + + int pageIndex = taskQueryParamDto.getPageNum() - 1; + int pageSize = taskQueryParamDto.getPageSize(); + + Page pageResultDto = new Page<>(); + TaskQuery taskQuery = taskService.createTaskQuery().taskAssignee(assign).orderByTaskCreateTime().desc(); + if (StrUtil.isNotBlank(taskQueryParamDto.getProcessName())) { + List processInstanceList = runtimeService.createProcessInstanceQuery() + .processInstanceNameLikeIgnoreCase(taskQueryParamDto.getProcessName()) + .list(); + if (CollUtil.isNotEmpty(processInstanceList)) { + taskQuery.processInstanceIdIn(processInstanceList.stream() + .map(ProcessInstance::getProcessDefinitionId) + .collect(Collectors.toList())); + } + } + + if (ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime())) { + ZoneId zoneId = ZoneId.systemDefault(); + ZonedDateTime zonedBeforeDateTime = taskQueryParamDto.getTaskTime()[0].atZone(zoneId); + ZonedDateTime zonedAfterDateTime = taskQueryParamDto.getTaskTime()[1].atZone(zoneId); + Date beforeDate = Date.from(zonedBeforeDateTime.toInstant()); + Date afterDate = Date.from(zonedAfterDateTime.toInstant()); + taskQuery.taskCreatedBefore(afterDate).taskCreatedAfter(beforeDate); + } + + taskQuery.listPage(pageIndex * pageSize, pageSize).forEach(task -> { + String taskId = task.getId(); + String processInstanceId = task.getProcessInstanceId(); + log.debug("(taskId) " + task.getName() + " processInstanceId={} executrionId={}", processInstanceId, + task.getExecutionId()); + + Map taskServiceVariables = taskService.getVariables(taskId); + Map runtimeServiceVariables = runtimeService.getVariables(processInstanceId); + Map variables = runtimeService.getVariables(task.getExecutionId()); + log.debug("任务变量:{}", JSONUtil.toJsonStr(taskServiceVariables)); + log.debug("流程节点:{}", JSONUtil.toJsonStr(runtimeServiceVariables)); + log.debug("执行节点变量:{}", JSONUtil.toJsonStr(variables)); + + String taskDefinitionKey = task.getTaskDefinitionKey(); + String processDefinitionId = task.getProcessDefinitionId(); + String flowId = NodeUtil.getFlowId(processDefinitionId); + + TaskDto taskDto = new TaskDto(); + taskDto.setFlowId(flowId); + taskDto.setTaskCreateTime(task.getCreateTime()); + taskDto.setNodeId(taskDefinitionKey); + taskDto.setParamMap(taskServiceVariables); + taskDto.setProcessInstanceId(processInstanceId); + taskDto.setTaskId(taskId); + taskDto.setAssign(task.getAssignee()); + taskDto.setTaskName(task.getName()); + + taskDtoList.add(taskDto); + }); + + long count = taskQuery.count(); + + log.debug("当前有" + count + " 个任务:"); + + pageResultDto.setTotal(count); + pageResultDto.setRecords(taskDtoList); + + return R.ok(pageResultDto); + } + +} diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/controller/EngineProcessInstanceController.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/controller/EngineProcessInstanceController.java new file mode 100644 index 000000000..be2d2b0e5 --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/controller/EngineProcessInstanceController.java @@ -0,0 +1,71 @@ +package com.pig4cloud.pigx.flow.engine.controller; + +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.task.dto.IndexPageStatistics; +import com.pig4cloud.pigx.flow.task.dto.VariableQueryParamDto; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.HistoryService; +import org.flowable.engine.RuntimeService; +import org.flowable.engine.TaskService; +import org.flowable.engine.history.HistoricActivityInstanceQuery; +import org.flowable.task.api.TaskQuery; +import org.springframework.web.bind.annotation.*; + +import java.util.Map; + +/** + * 任务控制器 + */ +@RestController +@Slf4j +@RequiredArgsConstructor +@RequestMapping("/process-instance") +public class EngineProcessInstanceController { + + private final TaskService taskService; + + private final HistoryService historyService; + + private final RuntimeService runtimeService; + + /** + * 查询首页统计数量 + * @param userId 用户ID + * @return 统计结果 + */ + @GetMapping("querySimpleData") + public R querySimpleData(long userId) { + TaskQuery taskQuery = taskService.createTaskQuery(); + + // 待办数量 + long pendingNum = taskQuery.taskAssignee(String.valueOf(userId)).count(); + // 已完成任务 + HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService + .createHistoricActivityInstanceQuery(); + + long completedNum = historicActivityInstanceQuery.taskAssignee(String.valueOf(userId)).finished().count(); + + IndexPageStatistics indexPageStatistics = IndexPageStatistics.builder() + .pendingNum(pendingNum) + .completedNum(completedNum) + .build(); + + return R.ok(indexPageStatistics); + } + + /** + * 查询流程变量 + * @param paramDto 查询参数 + * @return 流程变量 + */ + @PostMapping("queryVariables") + public R queryVariables(@RequestBody VariableQueryParamDto paramDto) { + + Map variables = runtimeService.getVariables(paramDto.getExecutionId()); + + return R.ok(variables); + + } + +} diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/controller/EngineTaskController.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/controller/EngineTaskController.java new file mode 100644 index 000000000..a080892ab --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/controller/EngineTaskController.java @@ -0,0 +1,149 @@ +package com.pig4cloud.pigx.flow.engine.controller; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.task.dto.TaskParamDto; +import com.pig4cloud.pigx.flow.task.dto.TaskResultDto; +import com.pig4cloud.pigx.flow.task.dto.VariableQueryParamDto; +import com.pig4cloud.pigx.flow.task.utils.NodeUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.HistoryService; +import org.flowable.engine.RuntimeService; +import org.flowable.engine.TaskService; +import org.flowable.task.api.DelegationState; +import org.flowable.task.api.Task; +import org.flowable.task.api.TaskQuery; +import org.flowable.task.api.history.HistoricTaskInstance; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * 任务控制器 + */ +@RestController +@Slf4j +@RequiredArgsConstructor +@RequestMapping("/task") +public class EngineTaskController { + + private final TaskService taskService; + + private final HistoryService historyService; + + private final RuntimeService runtimeService; + + /** + * 查询任务变量 + * @param paramDto 参数DTO + * @return 变量Map + */ + @PostMapping("queryTaskVariables") + public R queryTaskVariables(@RequestBody VariableQueryParamDto paramDto) { + + List keyList = paramDto.getKeyList(); + if (CollUtil.isEmpty(keyList)) { + TaskQuery taskQuery = taskService.createTaskQuery(); + + Task task = taskQuery.taskId(paramDto.getTaskId()).singleResult(); + if (task == null) { + return R.failed("任务不存在"); + } + + Map variables = runtimeService.getVariables(task.getExecutionId()); + + return R.ok(variables); + } + + Map variables = taskService.getVariables(paramDto.getTaskId(), keyList); + return R.ok(variables); + + } + + /** + * 查询任务详情 + * @param taskId 任务ID + * @param userId 用户ID + * @return 任务结果DTO + */ + @GetMapping("queryTask") + public R queryTask(String taskId, String userId) { + Optional task = Optional + .ofNullable(taskService.createTaskQuery().taskId(taskId).taskAssignee(userId).singleResult()); + + if (task.isPresent()) { + String processDefinitionId = task.get().getProcessDefinitionId(); + String taskDefinitionKey = task.get().getTaskDefinitionKey(); + DelegationState delegationState = task.get().getDelegationState(); + String processInstanceId = task.get().getProcessInstanceId(); + Object delegateVariable = taskService.getVariableLocal(taskId, "delegate"); + + String flowId = NodeUtil.getFlowId(processDefinitionId); + Map variables = taskService.getVariables(taskId); + Map variableAll = new HashMap<>(variables); + + TaskResultDto taskResultDto = new TaskResultDto(); + taskResultDto.setFlowId(flowId); + taskResultDto.setProcessInstanceId(processDefinitionId); + taskResultDto.setNodeId(taskDefinitionKey); + taskResultDto.setCurrentTask(true); + taskResultDto.setDelegate(Convert.toBool(delegateVariable, false)); + taskResultDto.setVariableAll(variableAll); + taskResultDto.setProcessInstanceId(processInstanceId); + taskResultDto.setDelegationState(delegationState == null ? null : delegationState.toString()); + + return R.ok(taskResultDto); + } + else { + Optional historicTaskInstance = Optional + .ofNullable(historyService.createHistoricTaskInstanceQuery() + .taskId(taskId) + .taskAssignee(userId) + .singleResult()); + + if (historicTaskInstance.isPresent()) { + String processDefinitionId = historicTaskInstance.get().getProcessDefinitionId(); + String taskDefinitionKey = historicTaskInstance.get().getTaskDefinitionKey(); + String processInstanceId = historicTaskInstance.get().getProcessInstanceId(); + + String flowId = NodeUtil.getFlowId(processDefinitionId); + Map variableAll = new HashMap<>(); + + TaskResultDto taskResultDto = new TaskResultDto(); + taskResultDto.setFlowId(flowId); + taskResultDto.setNodeId(taskDefinitionKey); + taskResultDto.setCurrentTask(false); + taskResultDto.setVariableAll(variableAll); + taskResultDto.setProcessInstanceId(processInstanceId); + + return R.ok(taskResultDto); + } + else { + return R.failed("任务不存在"); + } + } + } + + /** + * 完成任务 + * @param taskParamDto 任务参数DTO + * @return 操作结果 + */ + @PostMapping("/complete") + public R complete(@RequestBody TaskParamDto taskParamDto) { + Map taskLocalParamMap = taskParamDto.getTaskLocalParamMap(); + if (CollUtil.isNotEmpty(taskLocalParamMap)) { + taskService.setVariablesLocal(taskParamDto.getTaskId(), taskLocalParamMap); + } + + taskService.complete(taskParamDto.getTaskId(), taskParamDto.getParamMap()); + + return R.ok(); + } + +} diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/ExpressionHandler.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/ExpressionHandler.java new file mode 100644 index 000000000..ef1729bd1 --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/ExpressionHandler.java @@ -0,0 +1,292 @@ +package com.pig4cloud.pigx.flow.engine.expression; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.lang.Dict; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.EscapeUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; +import com.googlecode.aviator.AviatorEvaluator; +import com.pig4cloud.pigx.admin.api.entity.SysUser; +import com.pig4cloud.pigx.admin.api.feign.RemoteUserService; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.task.constant.NodeUserTypeEnum; +import com.pig4cloud.pigx.flow.task.dto.NodeUser; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.delegate.DelegateExecution; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 表达式解析 + */ +@Component("expressionHandler") +@Slf4j +@RequiredArgsConstructor +public class ExpressionHandler { + + private final RemoteUserService remoteUserService; + + public Long getUserId(String key, DelegateExecution execution) { + Object variable = execution.getVariable(key); + NodeUser nodeUserDto = JSON.parseArray(JSON.toJSONString(variable), NodeUser.class).get(0); + return nodeUserDto.getId(); + } + + /** + * 日期时间比较 + * @param key + * @param symbol + * @param param + * @param execution + * @param format 时间格式化模式 + * @return + */ + public boolean dateTimeCompare(String key, String symbol, Object param, DelegateExecution execution, + String format) { + + Object value = execution.getVariable(key); + + log.debug("表单值:key={} value={}", key, JSON.toJSONString(value)); + log.debug("条件 标识:{} 参数:{} 格式:{}", symbol, JSON.toJSONString(param), format); + + // 表单值为空 + if (value == null) { + return false; + } + + long valueTime = DateUtil.parse(value.toString(), format).getTime(); + long paramTime = DateUtil.parse(param.toString(), format).getTime(); + + return compare(StrUtil.format("${key{}{}}", symbol, paramTime), Dict.create().set("key", valueTime)); + } + + /** + * 数字类型比较 + * @param key 表单key + * @param symbol 比较符号 + * @param param 表单参数 + * @param execution + * @return + */ + public boolean numberCompare(String key, String symbol, Object param, DelegateExecution execution) { + + Object value = execution.getVariable(key); + + log.debug("表单值:key={} value={}", key, JSON.toJSONString(value)); + log.debug("条件 标识:{} 参数:{}", symbol, JSON.toJSONString(param)); + + // 表单值为空 + if (value == null) { + return false; + } + + return compare(StrUtil.format("${key{}{}}", symbol, param), Dict.create().set("key", Convert.toNumber(value))); + + } + + private Boolean compare(String symbol, Dict value) { + Object result = AviatorEvaluator.getInstance().execute(symbol, value); + // 渲染结果 + log.debug("验证结果:{}", result); + return Convert.toBool(result, false); + } + + /** + * 日期类型对比 + * @param key 表单key + * @param symbol 比较符号 + * @param param 比较参数值 + * @param execution 上下午执行前 + * @param format 日期格式化字符串 + * @return + */ + public boolean dateCompare(String key, String symbol, Object param, DelegateExecution execution, String format) { + + Object value = execution.getVariable(key); + + log.debug("表单值:key={} value={}", key, JSON.toJSONString(value)); + log.debug("条件 标识:{} 参数:{}", symbol, JSON.toJSONString(param)); + + // 表单值为空 + if (value == null) { + return false; + } + + // 处理表单值 + DateTime valueDateTime = DateUtil.parse(value.toString(), format); + log.debug("表单值:{} 格式化显示:{}", valueDateTime.getTime(), DateUtil.formatDateTime(valueDateTime)); + // 处理参数值 + DateTime paramDateTime = DateUtil.parse(param.toString(), format); + log.debug("参数值:{} 格式化显示:{}", paramDateTime.getTime(), DateUtil.formatDateTime(paramDateTime)); + + // 获取模板 + return compare(StrUtil.format("${key{}{}}", symbol, paramDateTime.getTime()), + Dict.create().set("key", valueDateTime.getTime())); + + } + + /** + * 判断数字数组包含 + * @param key 表单key + * @param array 条件值 + * @return + */ + public boolean numberContain(String key, DelegateExecution execution, Object... array) { + + Object value = execution.getVariable(key); + + log.debug("表单值:key={} value={}", key, JSON.toJSONString(value)); + log.debug("条件 参数:{}", JSON.toJSONString(array)); + + if (value == null) { + return false; + } + + return numberContain(value, array); + } + + private static boolean numberContain(Object value, Object[] array) { + BigDecimal valueBigDecimal = Convert.toBigDecimal(value); + + for (Object aLong : array) { + if (valueBigDecimal.compareTo(Convert.toBigDecimal(aLong)) == 0) { + return true; + } + } + return false; + } + + /** + * 判断字符数组包含 + * @param key 表单key + * @param array 条件值 + * @return + */ + public boolean stringContain(String key, DelegateExecution execution, String... array) { + Object value = execution.getVariable(key); + + log.debug("表单值:key={} value={}", key, JSON.toJSONString(value)); + log.debug("条件 参数:{}", JSON.toJSONString(array)); + if (value == null) { + return false; + } + return ArrayUtil.contains(array, value.toString()); + } + + /** + * 字符串判断相等 + * @param key 表单key + * @param param 参数 + * @return + */ + public boolean stringEqual(String key, String param, DelegateExecution execution) { + Object value = execution.getVariable(key); + + log.debug("表单值:key={} value={}", key, JSON.toJSONString(value)); + log.debug("条件 参数:{}", JSON.toJSONString(param)); + if (value == null) { + return false; + } + return StrUtil.equals(value.toString(), param); + } + + public boolean deptCompare(String key, String param, String symbol, DelegateExecution execution) { + param = EscapeUtil.unescape(param); + + Object value = execution.getVariable(key); + + String jsonString = JSON.toJSONString(value); + log.debug("表单值:key={} value={} symbol={}", key, jsonString, symbol); + log.debug("条件 参数:{}", param); + if (value == null) { + return false; + } + + // 表单值 + List nodeUserDtoList = JSON.parseArray(jsonString, NodeUser.class); + if (CollUtil.isEmpty(nodeUserDtoList) || nodeUserDtoList.size() != 1) { + return false; + } + NodeUser nodeUserDto = nodeUserDtoList.get(0); + + // 参数 + List paramDeptList = JSON.parseArray(param, NodeUser.class); + Long deptId = nodeUserDto.getId(); + List deptIdList = paramDeptList.stream().map(NodeUser::getId).collect(Collectors.toList()); + + return inCompare(symbol, deptId, deptIdList); + + } + + private static boolean inCompare(String symbol, Long deptId, List deptIdList) { + if (StrUtil.equalsAny(symbol, "in", "==")) { + // 属于 + return deptIdList.contains(deptId); + } + if (StrUtil.equalsAny(symbol, "notin", "!=")) { + // 属于 + return !deptIdList.contains(deptId); + } + + return false; + } + + /** + * user判断 + * @param key 表单key + * @param param 参数 + * @return + */ + public boolean userCompare(String key, String param, String symbol, DelegateExecution execution) { + param = EscapeUtil.unescape(param); + + Object value = execution.getVariable(key); + + String jsonString = JSON.toJSONString(value); + log.debug("表单值:key={} value={} symbol={} ", key, jsonString, symbol); + log.debug("条件 参数:{}", param); + + if (value == null) { + return false; + } + + // 表单值 + List nodeUserDtoList = JSON.parseArray(jsonString, NodeUser.class); + + if (CollUtil.isEmpty(nodeUserDtoList) || nodeUserDtoList.size() != 1) { + return false; + } + + NodeUser nodeUserDto = nodeUserDtoList.get(0); + + // 参数 + List paramDeptList = JSON.parseArray(param, NodeUser.class); + + List deptIdList = paramDeptList.stream() + .filter(w -> StrUtil.equals(w.getType(), NodeUserTypeEnum.DEPT.getKey())) + .map(NodeUser::getId) + .collect(Collectors.toList()); + + List userIdList = paramDeptList.stream() + .filter(w -> StrUtil.equals(w.getType(), NodeUserTypeEnum.USER.getKey())) + .map(NodeUser::getId) + .collect(Collectors.toList()); + + if (CollUtil.isNotEmpty(deptIdList)) { + R> r = remoteUserService.getUserIdListByDeptIdList(deptIdList); + List data = r.getData().stream().map(SysUser::getUserId).toList(); + userIdList.addAll(data); + } + + return inCompare(symbol, Convert.toLong(nodeUserDto.getId()), userIdList); + } + +} diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/NodeConditionStrategy.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/NodeConditionStrategy.java new file mode 100644 index 000000000..6eca2fd28 --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/NodeConditionStrategy.java @@ -0,0 +1,15 @@ +package com.pig4cloud.pigx.flow.engine.expression.condition; + +import com.pig4cloud.pigx.flow.task.dto.Condition; + +/** + * 节点单个条件处理器 + */ +public interface NodeConditionStrategy { + + /** + * 抽象方法 处理表达式 + */ + String handle(Condition condition); + +} diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/NodeExpressionStrategyFactory.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/NodeExpressionStrategyFactory.java new file mode 100644 index 000000000..20d5b617d --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/NodeExpressionStrategyFactory.java @@ -0,0 +1,106 @@ +package com.pig4cloud.pigx.flow.engine.expression.condition; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.spring.SpringUtil; +import com.pig4cloud.pigx.flow.task.dto.Condition; +import com.pig4cloud.pigx.flow.task.dto.GroupCondition; +import com.pig4cloud.pigx.flow.task.dto.Node; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class NodeExpressionStrategyFactory { + + public static String handleSingleCondition(Condition nodeConditionDto) { + Map nodeConditionStrategyMap = SpringUtil + .getBeansOfType(NodeConditionStrategy.class); + NodeConditionStrategy nodeConditionHandler = nodeConditionStrategyMap + .get(nodeConditionDto.getKeyType() + "NodeConditionStrategy"); + if (nodeConditionHandler == null) { + return "(1==1)"; + } + return nodeConditionHandler.handle(nodeConditionDto); + } + + /** + * 组内处理表达式 + * @param groupDto + * @return + */ + public static String handleGroupCondition(GroupCondition groupDto) { + + List exps = new ArrayList<>(); + + for (Condition condition : groupDto.getConditionList()) { + String singleExpression = handleSingleCondition(condition); + exps.add(singleExpression); + } + Boolean mode = groupDto.getMode(); + + if (!mode) { + String join = CollUtil.join(exps, "||"); + + return "(" + join + ")"; + } + + String join = CollUtil.join(exps, "&&"); + return "(" + join + ")"; + } + + /** + * 处理单个分支表达式 + * @return + */ + public static String handle(Node node) { + + List exps = new ArrayList<>(); + + List groups = node.getConditionList(); + if (CollUtil.isEmpty(groups)) { + return "${1==1}"; + } + for (GroupCondition group : groups) { + String s = handleGroupCondition(group); + exps.add(s); + } + + if (!node.getGroupMode()) { + String join = CollUtil.join(exps, "||"); + return "${(" + join + ")}"; + } + + String join = CollUtil.join(exps, "&&"); + return "${(" + join + ")}"; + } + + /** + * 处理默认分支表达式 + * @param branchs 所有分支 + * @return + */ + public static String handleDefaultBranch(List branchs) { + + List expList = new ArrayList<>(); + + int size = branchs.size(); + + int index = 1; + for (Node branch : branchs) { + + if (index == size) { + continue; + } + + String exp = handle(branch); + String s = StrUtil.subBetween(exp, "${", "}"); + expList.add(StrUtil.format("({})", s)); + + index++; + } + String join = StrUtil.format("!({})", CollUtil.join(expList, "||")); + return "${" + join + "}"; + } + +} diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/impl/DateNodeConditionStrategy.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/impl/DateNodeConditionStrategy.java new file mode 100644 index 000000000..85a17089f --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/impl/DateNodeConditionStrategy.java @@ -0,0 +1,29 @@ +package com.pig4cloud.pigx.flow.engine.expression.condition.impl; + +import cn.hutool.core.util.StrUtil; +import com.pig4cloud.pigx.flow.engine.expression.condition.NodeConditionStrategy; +import com.pig4cloud.pigx.flow.task.dto.Condition; +import org.springframework.stereotype.Component; + +/** + * 字符类型处理器 + */ +@Component("DateNodeConditionStrategy") +public class DateNodeConditionStrategy implements NodeConditionStrategy { + + /** + * 抽象方法 处理表达式 + */ + @Override + public String handle(Condition condition) { + + String compare = condition.getExpression(); + String id = condition.getKey(); + Object value = condition.getValue(); + + return StrUtil.format("(expressionHandler.dateTimeCompare(\"{}\",\"{}\",\"{}\",execution,\"yyyy-MM-dd\"))", id, + compare, value); + + } + +} diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/impl/DateTimeNodeConditionStrategy.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/impl/DateTimeNodeConditionStrategy.java new file mode 100644 index 000000000..c6e891525 --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/impl/DateTimeNodeConditionStrategy.java @@ -0,0 +1,30 @@ +package com.pig4cloud.pigx.flow.engine.expression.condition.impl; + +import cn.hutool.core.util.StrUtil; +import com.pig4cloud.pigx.flow.engine.expression.condition.NodeConditionStrategy; +import com.pig4cloud.pigx.flow.task.dto.Condition; +import org.springframework.stereotype.Component; + +/** + * 字符类型处理器 + */ +@Component("DateTimeNodeConditionStrategy") +public class DateTimeNodeConditionStrategy implements NodeConditionStrategy { + + /** + * 抽象方法 处理表达式 + */ + @Override + public String handle(Condition condition) { + + String compare = condition.getExpression(); + String id = condition.getKey(); + Object value = condition.getValue(); + + return StrUtil.format( + "(expressionHandler.dateTimeCompare(\"{}\",\"{}\",\"{}\",execution,\"yyyy-MM-dd " + "HH:mm:ss\"))", id, + compare, value); + + } + +} diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/impl/InputNodeConditionStrategy.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/impl/InputNodeConditionStrategy.java new file mode 100644 index 000000000..8a230c165 --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/impl/InputNodeConditionStrategy.java @@ -0,0 +1,33 @@ +package com.pig4cloud.pigx.flow.engine.expression.condition.impl; + +import cn.hutool.core.util.StrUtil; +import com.pig4cloud.pigx.flow.engine.expression.condition.NodeConditionStrategy; +import com.pig4cloud.pigx.flow.task.dto.Condition; +import org.springframework.stereotype.Component; + +/** + * 字符类型处理器 + */ +@Component("InputNodeConditionStrategy") +public class InputNodeConditionStrategy implements NodeConditionStrategy { + + /** + * 抽象方法 处理表达式 + * + */ + @Override + public String handle(Condition condition) { + + String compare = condition.getExpression(); + String id = condition.getKey(); + Object value = condition.getValue(); + if (StrUtil.equals(compare, "==")) { + return StrUtil.format("(expressionHandler.stringEqual(\"{}\",\"{}\",execution))", id, value); + } + if (StrUtil.equals(compare, "!=")) { + return StrUtil.format("(!expressionHandler.stringEqual(\"{}\",\"{}\",execution))", id, value); + } + return "(2==2)"; + } + +} diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/impl/MoneyNodeConditionStrategy.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/impl/MoneyNodeConditionStrategy.java new file mode 100644 index 000000000..90e720521 --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/impl/MoneyNodeConditionStrategy.java @@ -0,0 +1,28 @@ +package com.pig4cloud.pigx.flow.engine.expression.condition.impl; + +import cn.hutool.core.util.StrUtil; +import com.pig4cloud.pigx.flow.engine.expression.condition.NodeConditionStrategy; +import com.pig4cloud.pigx.flow.task.dto.Condition; +import org.springframework.stereotype.Component; + +/** + * 字符类型处理器 + */ +@Component("MoneyNodeConditionStrategy") +public class MoneyNodeConditionStrategy implements NodeConditionStrategy { + + /** + * 抽象方法 处理表达式 + */ + @Override + public String handle(Condition condition) { + + String compare = condition.getExpression(); + String id = condition.getKey(); + Object value = condition.getValue(); + + return StrUtil.format("(expressionHandler.numberCompare(\"{}\",\"{}\",{},execution))", id, compare, value); + + } + +} diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/impl/NumberNodeConditionStrategy.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/impl/NumberNodeConditionStrategy.java new file mode 100644 index 000000000..a55086c55 --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/impl/NumberNodeConditionStrategy.java @@ -0,0 +1,28 @@ +package com.pig4cloud.pigx.flow.engine.expression.condition.impl; + +import cn.hutool.core.util.StrUtil; +import com.pig4cloud.pigx.flow.engine.expression.condition.NodeConditionStrategy; +import com.pig4cloud.pigx.flow.task.dto.Condition; +import org.springframework.stereotype.Component; + +/** + * 字符类型处理器 + */ +@Component("NumberNodeConditionStrategy") +public class NumberNodeConditionStrategy implements NodeConditionStrategy { + + /** + * 抽象方法 处理表达式 + */ + @Override + public String handle(Condition condition) { + + String compare = condition.getExpression(); + String id = condition.getKey(); + Object value = condition.getValue(); + + return StrUtil.format("(expressionHandler.numberCompare(\"{}\",\"{}\",{},execution))", id, compare, value); + + } + +} diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/impl/SelectDeptNodeConditionStrategy.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/impl/SelectDeptNodeConditionStrategy.java new file mode 100644 index 000000000..bf3f76953 --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/impl/SelectDeptNodeConditionStrategy.java @@ -0,0 +1,31 @@ +package com.pig4cloud.pigx.flow.engine.expression.condition.impl; + +import cn.hutool.core.util.EscapeUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; +import com.pig4cloud.pigx.flow.engine.expression.condition.NodeConditionStrategy; +import com.pig4cloud.pigx.flow.task.dto.Condition; +import org.springframework.stereotype.Component; + +/** + * 字符类型处理器 + */ +@Component("SelectDeptNodeConditionStrategy") +public class SelectDeptNodeConditionStrategy implements NodeConditionStrategy { + + /** + * 抽象方法 处理表达式 + */ + @Override + public String handle(Condition condition) { + + String compare = condition.getExpression(); + String id = condition.getKey(); + Object value = condition.getValue(); + + return StrUtil.format("(expressionHandler.deptCompare(\"{}\",\"{}\",\"{}\", execution))", id, + EscapeUtil.escape(JSON.toJSONString(value)), compare); + + } + +} diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/impl/SelectUserNodeConditionStrategy.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/impl/SelectUserNodeConditionStrategy.java new file mode 100644 index 000000000..61672ed02 --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/impl/SelectUserNodeConditionStrategy.java @@ -0,0 +1,31 @@ +package com.pig4cloud.pigx.flow.engine.expression.condition.impl; + +import cn.hutool.core.util.EscapeUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; +import com.pig4cloud.pigx.flow.engine.expression.condition.NodeConditionStrategy; +import com.pig4cloud.pigx.flow.task.dto.Condition; +import org.springframework.stereotype.Component; + +/** + * 字符类型处理器 + */ +@Component("SelectUserNodeConditionStrategy") +public class SelectUserNodeConditionStrategy implements NodeConditionStrategy { + + /** + * 抽象方法 处理表达式 + */ + @Override + public String handle(Condition condition) { + + String compare = condition.getExpression(); + String id = condition.getKey(); + Object value = condition.getValue(); + + return StrUtil.format("(expressionHandler.userCompare(\"{}\",\"{}\",\"{}\", execution))", id, + EscapeUtil.escape(JSON.toJSONString(value)), compare); + + } + +} diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/impl/SingleSelectNodeConditionStrategy.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/impl/SingleSelectNodeConditionStrategy.java new file mode 100644 index 000000000..75e3fb082 --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/impl/SingleSelectNodeConditionStrategy.java @@ -0,0 +1,47 @@ +package com.pig4cloud.pigx.flow.engine.expression.condition.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.StrUtil; +import com.pig4cloud.pigx.flow.engine.expression.condition.NodeConditionStrategy; +import com.pig4cloud.pigx.flow.task.dto.Condition; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 字符类型处理器 + */ +@Component("SingleSelectNodeConditionStrategy") +public class SingleSelectNodeConditionStrategy implements NodeConditionStrategy { + + /** + * 抽象方法 处理表达式 + */ + @Override + public String handle(Condition condition) { + + String compare = condition.getExpression(); + String id = condition.getKey(); + Object value = condition.getValue(); + + List list = Convert.toList(value); + + StringBuilder sb = new StringBuilder(); + + for (Object o : list) { + sb.append(",\"").append(o.toString()).append("\""); + } + String string = sb.toString(); + if (CollUtil.isNotEmpty(list)) { + string = string.substring(1); + } + if (compare.equals("in")) { + return StrUtil.format("(expressionHandler.stringContain(\"{}\", execution,{}))", id, string); + } + + return StrUtil.format("(!expressionHandler.stringContain(\"{}\", execution,{}))", id, string); + + } + +} diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/impl/TextareaNodeConditionStrategy.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/impl/TextareaNodeConditionStrategy.java new file mode 100644 index 000000000..d4c8b219d --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/impl/TextareaNodeConditionStrategy.java @@ -0,0 +1,33 @@ +package com.pig4cloud.pigx.flow.engine.expression.condition.impl; + +import cn.hutool.core.util.StrUtil; +import com.pig4cloud.pigx.flow.engine.expression.condition.NodeConditionStrategy; +import com.pig4cloud.pigx.flow.task.dto.Condition; +import org.springframework.stereotype.Component; + +/** + * 字符类型处理器 + */ +@Component("TextareaNodeConditionStrategy") +public class TextareaNodeConditionStrategy implements NodeConditionStrategy { + + /** + * 抽象方法 处理表达式 + * + */ + @Override + public String handle(Condition condition) { + + String compare = condition.getExpression(); + String id = condition.getKey(); + Object value = condition.getValue(); + if (StrUtil.equals(compare, "==")) { + return StrUtil.format("(expressionHandler.stringEqual(\"{}\",\"{}\",execution))", id, value); + } + if (StrUtil.equals(compare, "!=")) { + return StrUtil.format("(!expressionHandler.stringEqual(\"{}\",\"{}\",execution))", id, value); + } + return "(2==2)"; + } + +} diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/impl/TimeNodeConditionStrategy.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/impl/TimeNodeConditionStrategy.java new file mode 100644 index 000000000..44db0c2f0 --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/expression/condition/impl/TimeNodeConditionStrategy.java @@ -0,0 +1,29 @@ +package com.pig4cloud.pigx.flow.engine.expression.condition.impl; + +import cn.hutool.core.util.StrUtil; +import com.pig4cloud.pigx.flow.engine.expression.condition.NodeConditionStrategy; +import com.pig4cloud.pigx.flow.task.dto.Condition; +import org.springframework.stereotype.Component; + +/** + * 字符类型处理器 + */ +@Component("TimeNodeConditionStrategy") +public class TimeNodeConditionStrategy implements NodeConditionStrategy { + + /** + * 抽象方法 处理表达式 + */ + @Override + public String handle(Condition condition) { + + String compare = condition.getExpression(); + String id = condition.getKey(); + Object value = condition.getValue(); + + return StrUtil.format("(expressionHandler.dateTimeCompare(\"{}\",\"{}\",\"{}\",execution,\"HH:mm:ss\"))", id, + compare, value); + + } + +} diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/listeners/ApprovalCreateListener.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/listeners/ApprovalCreateListener.java new file mode 100644 index 000000000..04766081d --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/listeners/ApprovalCreateListener.java @@ -0,0 +1,91 @@ +package com.pig4cloud.pigx.flow.engine.listeners; + +import cn.hutool.core.lang.Dict; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.spring.SpringUtil; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.task.api.feign.RemoteFlowTaskService; +import com.pig4cloud.pigx.flow.task.constant.ProcessInstanceConstant; +import com.pig4cloud.pigx.flow.task.dto.Nobody; +import com.pig4cloud.pigx.flow.task.dto.Node; +import com.pig4cloud.pigx.flow.task.dto.NodeUser; +import com.pig4cloud.pigx.flow.task.utils.NodeUtil; +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.TaskService; +import org.flowable.task.service.delegate.DelegateTask; +import org.flowable.task.service.delegate.TaskListener; +import org.flowable.task.service.impl.persistence.entity.TaskEntityImpl; + +/** + * 审批创建监听器 + */ +@Slf4j +public class ApprovalCreateListener implements TaskListener { + + /** + * 当任务被触发时,执行该方法 + * @param delegateTask 委派的任务对象 + */ + @Override + public void notify(DelegateTask delegateTask) { + log.debug(delegateTask.getClass().getCanonicalName()); + TaskService taskService = SpringUtil.getBean(TaskService.class); + + String assignee = delegateTask.getAssignee(); + String name = delegateTask.getName(); + log.debug("任务{}-执行人:{}", name, assignee); + TaskEntityImpl taskEntity = (TaskEntityImpl) delegateTask; + String nodeId = taskEntity.getTaskDefinitionKey(); + String processDefinitionId = taskEntity.getProcessDefinitionId(); + + // 获取流程id + String flowId = NodeUtil.getFlowId(processDefinitionId); + + if (StrUtil.isBlank(assignee) + || StrUtil.equals(ProcessInstanceConstant.DEFAULT_EMPTY_ASSIGN.toString(), assignee)) { + + RemoteFlowTaskService remoteFlowTaskService = SpringUtil.getBean(RemoteFlowTaskService.class); + + // 查询节点原始数据 + Node node = remoteFlowTaskService.queryNodeOriData(flowId, nodeId).getData(); + + Nobody nobody = node.getNobody(); + + String handler = nobody.getHandler(); + + if (StrUtil.equals(handler, ProcessInstanceConstant.USER_TASK_NOBODY_HANDLER_TO_PASS)) { + // 直接通过 + Dict param = Dict.create().set(StrUtil.format("{}_approve_condition", nodeId), true); + taskService.complete(taskEntity.getId(), param); + } + + if (StrUtil.equals(handler, ProcessInstanceConstant.USER_TASK_NOBODY_HANDLER_TO_ADMIN)) { + // 指派给管理员 + + R longR = remoteFlowTaskService.queryProcessAdmin(flowId); + + Long adminId = longR.getData(); + + taskService.setAssignee(taskEntity.getId(), String.valueOf(adminId)); + } + + if (StrUtil.equals(handler, ProcessInstanceConstant.USER_TASK_NOBODY_HANDLER_TO_USER)) { + // 指定用户 + + NodeUser nodeUser = nobody.getAssignedUser().get(0); + + taskService.setAssignee(taskEntity.getId(), nodeUser.getId().toString()); + } + + if (StrUtil.equals(handler, ProcessInstanceConstant.USER_TASK_NOBODY_HANDLER_TO_END)) { + // 结束 + Dict param = Dict.create().set(StrUtil.format("{}_approve_condition", nodeId), false); + taskService.complete(taskEntity.getId(), param); + + } + + } + + } + +} diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/listeners/FlowProcessEventListener.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/listeners/FlowProcessEventListener.java new file mode 100644 index 000000000..8dd261ab3 --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/listeners/FlowProcessEventListener.java @@ -0,0 +1,288 @@ +package com.pig4cloud.pigx.flow.engine.listeners; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.spring.SpringUtil; +import com.alibaba.fastjson.JSON; +import com.pig4cloud.pigx.flow.task.api.feign.RemoteFlowTaskService; +import com.pig4cloud.pigx.flow.task.dto.*; +import com.pig4cloud.pigx.flow.task.utils.NodeUtil; +import lombok.extern.slf4j.Slf4j; +import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType; +import org.flowable.common.engine.api.delegate.event.FlowableEntityEvent; +import org.flowable.common.engine.api.delegate.event.FlowableEvent; +import org.flowable.common.engine.api.delegate.event.FlowableEventListener; +import org.flowable.engine.TaskService; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.delegate.event.impl.FlowableActivityEventImpl; +import org.flowable.engine.delegate.event.impl.FlowableMultiInstanceActivityCompletedEventImpl; +import org.flowable.engine.delegate.event.impl.FlowableProcessStartedEventImpl; +import org.flowable.engine.delegate.event.impl.FlowableProcessTerminatedEventImpl; +import org.flowable.engine.impl.persistence.entity.ExecutionEntityImpl; +import org.flowable.task.api.DelegationState; +import org.flowable.task.service.impl.persistence.entity.TaskEntityImpl; +import org.flowable.variable.api.event.FlowableVariableEvent; + +import java.util.Map; + +/** + * 流程监听器 + */ +@Slf4j +public class FlowProcessEventListener implements FlowableEventListener { + + /** + * 当事件被触发时调用 + * @param event 事件对象 + */ + @Override + public void onEvent(FlowableEvent event) { + RemoteFlowTaskService remoteFlowTaskService = SpringUtil.getBean(RemoteFlowTaskService.class); + + log.info("分支监听器 类型={} class={}", event.getType(), event.getClass().getCanonicalName()); + if (event.getType().toString().equals(FlowableEngineEventType.ACTIVITY_STARTED.toString())) { + // 节点开始执行 + FlowableActivityEventImpl flowableActivityEvent = (FlowableActivityEventImpl) event; + String activityId = flowableActivityEvent.getActivityId(); + String activityName = flowableActivityEvent.getActivityName(); + log.info("节点id:{} 名字:{}", activityId, activityName); + + String processInstanceId = flowableActivityEvent.getProcessInstanceId(); + + String processDefinitionId = flowableActivityEvent.getProcessDefinitionId(); + String flowId = NodeUtil.getFlowId(processDefinitionId); + + Node node = remoteFlowTaskService.queryNodeOriData(flowId, activityId).getData(); + + ProcessNodeRecordParamDto processNodeRecordParamDto = new ProcessNodeRecordParamDto(); + processNodeRecordParamDto.setFlowId(flowId); + processNodeRecordParamDto.setProcessInstanceId(processInstanceId); + processNodeRecordParamDto.setNodeId(activityId); + if (node != null) { + processNodeRecordParamDto.setNodeType(String.valueOf(node.getType())); + } + processNodeRecordParamDto.setNodeName(activityName); + processNodeRecordParamDto.setExecutionId(flowableActivityEvent.getExecutionId()); + remoteFlowTaskService.startNodeEvent(processNodeRecordParamDto); + } + + if (event.getType() + .toString() + .equals(FlowableEngineEventType.MULTI_INSTANCE_ACTIVITY_COMPLETED_WITH_CONDITION.toString()) + || event.getType() + .toString() + .equals(FlowableEngineEventType.MULTI_INSTANCE_ACTIVITY_COMPLETED.toString())) { + // 多实例任务 + FlowableMultiInstanceActivityCompletedEventImpl flowableActivityEvent = (FlowableMultiInstanceActivityCompletedEventImpl) event; + String activityId = flowableActivityEvent.getActivityId(); + String activityName = flowableActivityEvent.getActivityName(); + log.info("节点id:{} 名字:{}", activityId, activityName); + + String processInstanceId = flowableActivityEvent.getProcessInstanceId(); + + String processDefinitionId = flowableActivityEvent.getProcessDefinitionId(); + String flowId = NodeUtil.getFlowId(processDefinitionId); + + ProcessNodeRecordParamDto processNodeRecordParamDto = new ProcessNodeRecordParamDto(); + processNodeRecordParamDto.setFlowId(flowId); + processNodeRecordParamDto.setExecutionId(flowableActivityEvent.getExecutionId()); + processNodeRecordParamDto.setProcessInstanceId(processInstanceId); + // processNodeRecordParamDto.setData(JSON.toJSONString(processVariables)); + processNodeRecordParamDto.setNodeId(activityId); + // processNodeRecordParamDto.setNodeType(nodeDto.getType()); + processNodeRecordParamDto.setNodeName(activityName); + + remoteFlowTaskService.endNodeEvent(processNodeRecordParamDto); + } + if (event.getType().toString().equals(FlowableEngineEventType.ACTIVITY_COMPLETED.toString())) { + // 节点完成执行 + + FlowableActivityEventImpl flowableActivityEvent = (FlowableActivityEventImpl) event; + String activityId = flowableActivityEvent.getActivityId(); + String activityName = flowableActivityEvent.getActivityName(); + log.info("节点id:{} 名字:{}", activityId, activityName); + + String processInstanceId = flowableActivityEvent.getProcessInstanceId(); + + String processDefinitionId = flowableActivityEvent.getProcessDefinitionId(); + String flowId = NodeUtil.getFlowId(processDefinitionId); + + ProcessNodeRecordParamDto processNodeRecordParamDto = new ProcessNodeRecordParamDto(); + processNodeRecordParamDto.setFlowId(flowId); + processNodeRecordParamDto.setExecutionId(flowableActivityEvent.getExecutionId()); + processNodeRecordParamDto.setProcessInstanceId(processInstanceId); + // processNodeRecordParamDto.setData(JSON.toJSONString(processVariables)); + processNodeRecordParamDto.setNodeId(activityId); + // processNodeRecordParamDto.setNodeType(nodeDto.getType()); + processNodeRecordParamDto.setNodeName(activityName); + + remoteFlowTaskService.endNodeEvent(processNodeRecordParamDto); + + } + + if (event.getType().toString().equals(FlowableEngineEventType.VARIABLE_UPDATED.toString())) { + // 变量变化了 + FlowableVariableEvent flowableVariableEvent = (FlowableVariableEvent) event; + log.debug("变量[{}]变化了:{} ", flowableVariableEvent.getVariableName(), + flowableVariableEvent.getVariableValue()); + } + + if (event.getType().toString().equals(FlowableEngineEventType.VARIABLE_CREATED.toString())) { + // 变量创建了 + FlowableVariableEvent flowableVariableEvent = (FlowableVariableEvent) event; + log.debug("变量[{}]创建了:{} ", flowableVariableEvent.getVariableName(), + flowableVariableEvent.getVariableValue()); + } + if (event.getType().toString().equals(FlowableEngineEventType.VARIABLE_DELETED.toString())) { + // 变量删除了 + FlowableVariableEvent flowableVariableEvent = (FlowableVariableEvent) event; + log.debug("变量[{}]删除了:{} ", flowableVariableEvent.getVariableName(), + flowableVariableEvent.getVariableValue()); + } + if (event.getType() + .toString() + .equals(FlowableEngineEventType.PROCESS_COMPLETED_WITH_TERMINATE_END_EVENT.toString())) { + // 流程开完成 + FlowableProcessTerminatedEventImpl e = (FlowableProcessTerminatedEventImpl) event; + DelegateExecution execution = e.getExecution(); + String processInstanceId = e.getProcessInstanceId(); + ExecutionEntityImpl entity = (ExecutionEntityImpl) e.getEntity(); + + ProcessInstanceParamDto processInstanceParamDto = new ProcessInstanceParamDto(); + processInstanceParamDto.setProcessInstanceId(processInstanceId); + remoteFlowTaskService.endProcessEvent(processInstanceParamDto); + + } + + if (event.getType().toString().equals(FlowableEngineEventType.TASK_COMPLETED.toString())) { + + TaskService taskService = SpringUtil.getBean(TaskService.class); + + // 任务完成 + FlowableEntityEvent flowableEntityEvent = (FlowableEntityEvent) event; + TaskEntityImpl task = (TaskEntityImpl) flowableEntityEvent.getEntity(); + // 执行人id + String assignee = task.getAssignee(); + + // nodeid + String taskDefinitionKey = task.getTaskDefinitionKey(); + + // 实例id + String processInstanceId = task.getProcessInstanceId(); + + String processDefinitionId = task.getProcessDefinitionId(); + // 流程id + String flowId = NodeUtil.getFlowId(processDefinitionId); + ProcessNodeRecordAssignUserParamDto processNodeRecordAssignUserParamDto = new ProcessNodeRecordAssignUserParamDto(); + processNodeRecordAssignUserParamDto.setFlowId(flowId); + processNodeRecordAssignUserParamDto.setProcessInstanceId(processInstanceId); + processNodeRecordAssignUserParamDto.setData(JSON.toJSONString(taskService.getVariables(task.getId()))); + processNodeRecordAssignUserParamDto + .setLocalData(JSON.toJSONString(taskService.getVariablesLocal(task.getId()))); + processNodeRecordAssignUserParamDto.setNodeId(taskDefinitionKey); + processNodeRecordAssignUserParamDto.setUserId(Long.parseLong(assignee)); + processNodeRecordAssignUserParamDto.setTaskId(task.getId()); + processNodeRecordAssignUserParamDto.setNodeName(task.getName()); + processNodeRecordAssignUserParamDto.setTaskType("COMPLETE"); + processNodeRecordAssignUserParamDto.setApproveDesc(Convert.toStr(task.getVariableLocal("approveDesc"))); + processNodeRecordAssignUserParamDto.setExecutionId(task.getExecutionId()); + + remoteFlowTaskService.taskEndEvent(processNodeRecordAssignUserParamDto); + + } + if (event.getType().toString().equals(FlowableEngineEventType.TASK_ASSIGNED.toString())) { + // 任务被指派了人员 + FlowableEntityEvent flowableEntityEvent = (FlowableEntityEvent) event; + TaskEntityImpl task = (TaskEntityImpl) flowableEntityEvent.getEntity(); + // 执行人id + String assignee = task.getAssignee(); + // 任务拥有者 + String owner = task.getOwner(); + // + String delegationStateString = task.getDelegationStateString(); + + // nodeid + String taskDefinitionKey = task.getTaskDefinitionKey(); + + // 实例id + String processInstanceId = task.getProcessInstanceId(); + + String processDefinitionId = task.getProcessDefinitionId(); + // 流程id + String flowId = NodeUtil.getFlowId(processDefinitionId); + ProcessNodeRecordAssignUserParamDto processNodeRecordAssignUserParamDto = new ProcessNodeRecordAssignUserParamDto(); + processNodeRecordAssignUserParamDto.setFlowId(flowId); + processNodeRecordAssignUserParamDto.setProcessInstanceId(processInstanceId); + // processNodeRecordAssignUserParamDto.setData(); + processNodeRecordAssignUserParamDto.setNodeId(taskDefinitionKey); + processNodeRecordAssignUserParamDto.setUserId(Long.parseLong(assignee)); + processNodeRecordAssignUserParamDto.setTaskId(task.getId()); + processNodeRecordAssignUserParamDto.setNodeName(task.getName()); + processNodeRecordAssignUserParamDto + .setTaskType(StrUtil.equals(DelegationState.PENDING.toString(), delegationStateString) ? "DELEGATION" + : (StrUtil.equals(DelegationState.RESOLVED.toString(), delegationStateString) ? "RESOLVED" + : "")); + processNodeRecordAssignUserParamDto.setApproveDesc(Convert.toStr(task.getVariableLocal("approveDesc"))); + processNodeRecordAssignUserParamDto.setExecutionId(task.getExecutionId()); + + remoteFlowTaskService.startAssignUser(processNodeRecordAssignUserParamDto); + + } + + if (event.getType().toString().equals(FlowableEngineEventType.PROCESS_STARTED.toString())) { + // 流程开始了 + FlowableProcessStartedEventImpl flowableProcessStartedEvent = (FlowableProcessStartedEventImpl) event; + + ExecutionEntityImpl entity = (ExecutionEntityImpl) flowableProcessStartedEvent.getEntity(); + DelegateExecution execution = flowableProcessStartedEvent.getExecution(); + String processInstanceId = flowableProcessStartedEvent.getProcessInstanceId(); + { + // 上级实例id + String nestedProcessInstanceId = flowableProcessStartedEvent.getNestedProcessInstanceId(); + + String flowId = entity.getProcessDefinitionKey(); + + Object variable = execution.getVariable("root"); + Long startUserId = JSON.parseArray(JSON.toJSONString(variable), NodeUser.class).get(0).getId(); + Map variables = execution.getVariables(); + + ProcessInstanceRecordParamDto processInstanceRecordParamDto = new ProcessInstanceRecordParamDto(); + processInstanceRecordParamDto.setUserId(startUserId); + processInstanceRecordParamDto.setParentProcessInstanceId(nestedProcessInstanceId); + processInstanceRecordParamDto.setFlowId(flowId); + processInstanceRecordParamDto.setProcessInstanceId(processInstanceId); + processInstanceRecordParamDto.setFormData(JSON.toJSONString(variables)); + remoteFlowTaskService.createProcessEvent(processInstanceRecordParamDto); + } + + } + } + + /** + * 如果监听器抛出异常是否终止当前操作 + * @return 是否终止当前操作 + */ + @Override + public boolean isFailOnException() { + return false; + } + + /** + * 返回监听器是否在事务生命周期事件发生时立即触发 + * @return 是否在事务生命周期事件上触发 + */ + @Override + public boolean isFireOnTransactionLifecycleEvent() { + return false; + } + + /** + * 如果非空,表示在当前事务的生命周期中的触发点 + * @return 事务生命周期中的触发点 + */ + @Override + public String getOnTransaction() { + return null; + } + +} diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/node/AssignUserStrategy.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/node/AssignUserStrategy.java new file mode 100644 index 000000000..2850070be --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/node/AssignUserStrategy.java @@ -0,0 +1,22 @@ +package com.pig4cloud.pigx.flow.engine.node; + +import com.pig4cloud.pigx.flow.task.dto.Node; +import com.pig4cloud.pigx.flow.task.dto.NodeUser; + +import java.util.List; +import java.util.Map; + +/** + * 指定用户策略处理器 + */ +public interface AssignUserStrategy { + + /** + * 抽象方法 处理表达式 + * @param node + * @param rootUser + * @param variables + */ + List handle(Node node, NodeUser rootUser, Map variables); + +} diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/node/MultiInstanceHandler.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/node/MultiInstanceHandler.java new file mode 100644 index 000000000..66200b63f --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/node/MultiInstanceHandler.java @@ -0,0 +1,126 @@ +package com.pig4cloud.pigx.flow.engine.node; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson2.JSON; +import com.pig4cloud.pigx.flow.task.api.feign.RemoteFlowTaskService; +import com.pig4cloud.pigx.flow.task.constant.ProcessInstanceConstant; +import com.pig4cloud.pigx.flow.task.dto.Node; +import com.pig4cloud.pigx.flow.task.dto.NodeUser; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.impl.persistence.entity.ExecutionEntityImpl; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +@Slf4j +@RequiredArgsConstructor +@Component("multiInstanceHandler") +public class MultiInstanceHandler { + + private final RemoteFlowTaskService remoteFlowTaskService; + + private final Map assignUserStrategyMap; + + /** + * 解析执行人 + * @param execution 流程执行对象 + * @return 执行人集合 + */ + public List resolveAssignee(DelegateExecution execution) { + // 执行人集合 + List assignList = new ArrayList<>(); + + ExecutionEntityImpl entity = (ExecutionEntityImpl) execution; + + String flowId = entity.getProcessDefinitionKey(); + String nodeId = entity.getActivityId(); + + log.debug("nodeId={} nodeName={}", nodeId, entity.getActivityName()); + + // 发起人 + Object rootUserObj = execution.getVariable("root"); + NodeUser rootUser = JSON.parseArray(JSON.toJSONString(rootUserObj), NodeUser.class).get(0); + + // 节点数据 + Node node = remoteFlowTaskService.queryNodeOriData(flowId, nodeId).getData(); + if (node != null) { + Map variables = execution.getVariables(); + Integer assignedType = node.getAssignedType(); + List userIdList = assignUserStrategyMap.get(assignedType + "AssignUserStrategy") + .handle(node, rootUser, variables); + assignList.addAll(userIdList); + } + else { + // 默认值 + String format = StrUtil.format("{}_assignee_default_list", nodeId); + Object variable = execution.getVariable(format); + List nodeUserDtos = JSON.parseArray(JSON.toJSONString(variable), NodeUser.class); + if (CollUtil.isNotEmpty(nodeUserDtos)) { + List collect = nodeUserDtos.stream().map(NodeUser::getId).toList(); + assignList.addAll(collect); + } + } + + Optional.of(assignList).orElseGet(() -> { + List defaultList = new ArrayList<>(); + defaultList.add(ProcessInstanceConstant.DEFAULT_EMPTY_ASSIGN); + return defaultList; + }); + + return assignList; + } + + /** + * 会签或者或签完成条件检查 检查节点是否满足会签或者或签的完成条件 + * @param execution 执行实例对象 + * @return boolean 如果节点满足条件则返回true,否则返回false + */ + public boolean completionCondition(DelegateExecution execution) { + ExecutionEntityImpl entity = (ExecutionEntityImpl) execution; + String processDefinitionKey = entity.getProcessDefinitionKey(); + String nodeId = execution.getCurrentActivityId(); + + Node node = remoteFlowTaskService.queryNodeOriData(processDefinitionKey, nodeId).getData(); + Integer multipleMode = node.getMultipleMode(); + BigDecimal modePercentage = BigDecimal.valueOf(100); + + Object variable = execution.getVariable(StrUtil.format("{}_approve_condition", nodeId)); + log.debug("当前节点审批结果:{}", variable); + Boolean approve = Convert.toBool(variable); + + if (multipleMode == ProcessInstanceConstant.MULTIPLE_MODE_AL_SAME + || multipleMode == ProcessInstanceConstant.MULTIPLE_MODE_ALL_SORT) { + // 如果是会签或者顺序签署 + if (!approve) { + return true; + } + } + + if (multipleMode == ProcessInstanceConstant.MULTIPLE_MODE_ONE) { + // 如果是或签 + if (approve) { + return true; + } + } + + int nrOfInstances = (int) execution.getVariable("nrOfInstances"); + int nrOfCompletedInstances = (int) execution.getVariable("nrOfCompletedInstances"); + log.debug("当前节点完成实例数:{} 总实例数:{} 需要完成比例:{}", nrOfCompletedInstances, nrOfInstances, modePercentage); + + if (multipleMode == ProcessInstanceConstant.MULTIPLE_MODE_AL_SAME) { + return BigDecimal.valueOf(nrOfCompletedInstances * 100L) + .compareTo(BigDecimal.valueOf(nrOfCompletedInstances).multiply(modePercentage)) > 0; + } + + return nrOfCompletedInstances == nrOfInstances; + } + +} diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/node/impl/AssignUserFixedStrategyImpl.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/node/impl/AssignUserFixedStrategyImpl.java new file mode 100644 index 000000000..63e1f893a --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/node/impl/AssignUserFixedStrategyImpl.java @@ -0,0 +1,70 @@ +package com.pig4cloud.pigx.flow.engine.node.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.pig4cloud.pigx.admin.api.entity.SysUser; +import com.pig4cloud.pigx.admin.api.feign.RemoteUserService; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.engine.node.AssignUserStrategy; +import com.pig4cloud.pigx.flow.task.constant.NodeUserTypeEnum; +import com.pig4cloud.pigx.flow.task.constant.ProcessInstanceConstant; +import com.pig4cloud.pigx.flow.task.dto.Node; +import com.pig4cloud.pigx.flow.task.dto.NodeUser; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 指定具体用户 + * + * @author Huijun Zhao + * @description + * @date 2023-07-07 13:42 + */ +@RequiredArgsConstructor +@Component(ProcessInstanceConstant.AssignedTypeClass.USER + "AssignUserStrategy") +public class AssignUserFixedStrategyImpl implements AssignUserStrategy { + + private final RemoteUserService remoteUserService; + + /** + * 处理节点并返回用户ID列表。 + * @param node 节点 + * @param rootUser 根用户 + * @param variables 变量 + * @return 用户ID列表 + */ + @Override + public List handle(Node node, NodeUser rootUser, Map variables) { + + // 指定人员 + List userDtoList = node.getNodeUserList(); + // 用户ID列表 + List userIdList = userDtoList.stream() + .filter(w -> StrUtil.equals(w.getType(), NodeUserTypeEnum.USER.getKey())) + .map(NodeUser::getId) + .collect(Collectors.toList()); + // 部门ID列表 + List deptIdList = userDtoList.stream() + .filter(w -> StrUtil.equals(w.getType(), NodeUserTypeEnum.DEPT.getKey())) + .map(NodeUser::getId) + .collect(Collectors.toList()); + + if (CollUtil.isNotEmpty(deptIdList)) { + R> r = remoteUserService.getUserIdListByDeptIdList(deptIdList); + if (CollUtil.isNotEmpty(r.getData())) { + for (SysUser user : r.getData()) { + if (!userIdList.contains(user.getUserId())) { + userIdList.add(user.getUserId()); + } + } + } + } + + return userIdList; + } + +} diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/node/impl/AssignUserFormStrategyImpl.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/node/impl/AssignUserFormStrategyImpl.java new file mode 100644 index 000000000..73ab30c93 --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/node/impl/AssignUserFormStrategyImpl.java @@ -0,0 +1,40 @@ +package com.pig4cloud.pigx.flow.engine.node.impl; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import com.alibaba.fastjson.JSON; +import com.pig4cloud.pigx.flow.engine.node.AssignUserStrategy; +import com.pig4cloud.pigx.flow.task.constant.ProcessInstanceConstant; +import com.pig4cloud.pigx.flow.task.dto.Node; +import com.pig4cloud.pigx.flow.task.dto.NodeUser; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 来自表单 + * + * @author Huijun Zhao + * @description + * @date 2023-07-07 13:42 + */ +@Component(ProcessInstanceConstant.AssignedTypeClass.FORM_USER + "AssignUserStrategy") +public class AssignUserFormStrategyImpl implements AssignUserStrategy { + + @Override + public List handle(Node node, NodeUser rootUser, Map variables) { + List assignList = new ArrayList<>(); + + Object variable = variables.get(node.getFormUserId()); + if (variable != null && !StrUtil.isBlankIfStr(variable)) { + String jsonString = JSON.toJSONString(variable); + List nodeUserDtoList = JSONUtil.toList(jsonString, NodeUser.class); + assignList.addAll(nodeUserDtoList.stream().map(NodeUser::getId).toList()); + } + + return assignList; + } + +} diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/node/impl/AssignUserRoleStrategyImpl.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/node/impl/AssignUserRoleStrategyImpl.java new file mode 100644 index 000000000..18e3a3100 --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/node/impl/AssignUserRoleStrategyImpl.java @@ -0,0 +1,51 @@ +package com.pig4cloud.pigx.flow.engine.node.impl; + +import com.pig4cloud.pigx.admin.api.feign.RemoteUserService; +import com.pig4cloud.pigx.common.core.util.RetOps; +import com.pig4cloud.pigx.flow.engine.node.AssignUserStrategy; +import com.pig4cloud.pigx.flow.task.constant.ProcessInstanceConstant; +import com.pig4cloud.pigx.flow.task.dto.Node; +import com.pig4cloud.pigx.flow.task.dto.NodeUser; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 来自角色 + * + * @author Huijun Zhao + * @description + * @date 2023-07-07 13:42 + */ +@RequiredArgsConstructor +@Component(ProcessInstanceConstant.AssignedTypeClass.ROLE + "AssignUserStrategy") +public class AssignUserRoleStrategyImpl implements AssignUserStrategy { + + private final RemoteUserService remoteUserService; + + /** + * 处理节点并返回用户ID列表。 + * @param node 节点 + * @param rootUser 根用户 + * @param variables 变量 + * @return 用户ID列表 + */ + @Override + public List handle(Node node, NodeUser rootUser, Map variables) { + // 使用 lambda 表达式和方法引用从 NodeUser 列表中提取角色 ID + List roleIds = node.getNodeUserList().stream().map(NodeUser::getId).collect(Collectors.toList()); + // 提取 Optional 结果中的数据 + List data = RetOps.of(remoteUserService.getUserIdListByRoleIdList(roleIds)) + .getData() + .orElseGet(Collections::emptyList); + + // 返回用户 ID 列表 + return new ArrayList<>(data); + } + +} diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/node/impl/AssignUserSelfSelectStrategyImpl.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/node/impl/AssignUserSelfSelectStrategyImpl.java new file mode 100644 index 000000000..df1de7327 --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/node/impl/AssignUserSelfSelectStrategyImpl.java @@ -0,0 +1,45 @@ +package com.pig4cloud.pigx.flow.engine.node.impl; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; +import com.pig4cloud.pigx.flow.engine.node.AssignUserStrategy; +import com.pig4cloud.pigx.flow.task.constant.ProcessInstanceConstant; +import com.pig4cloud.pigx.flow.task.dto.Node; +import com.pig4cloud.pigx.flow.task.dto.NodeUser; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 发起人自选 + * + * @author Huijun Zhao + * @description + * @date 2023-07-07 13:42 + */ +@Slf4j +@Component(ProcessInstanceConstant.AssignedTypeClass.SELF_SELECT + "AssignUserStrategy") +public class AssignUserSelfSelectStrategyImpl implements AssignUserStrategy { + + @Override + public List handle(Node node, NodeUser rootUser, Map variables) { + + List assignList = new ArrayList<>(); + + Object variable = variables.get(StrUtil.format("{}_assignee_select", node.getId())); + log.info("{}-发起人自选参数:{}", node.getName(), variable); + if (variable == null) { + return assignList; + } + List nodeUserDtos = JSON.parseArray(JSON.toJSONString(variable), NodeUser.class); + + List collect = nodeUserDtos.stream().map(NodeUser::getId).toList(); + + assignList.addAll(collect); + return assignList; + } + +} diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/node/impl/AssignUserSelfStrategyImpl.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/node/impl/AssignUserSelfStrategyImpl.java new file mode 100644 index 000000000..2c6227683 --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/node/impl/AssignUserSelfStrategyImpl.java @@ -0,0 +1,28 @@ +package com.pig4cloud.pigx.flow.engine.node.impl; + +import cn.hutool.core.collection.CollUtil; +import com.pig4cloud.pigx.flow.engine.node.AssignUserStrategy; +import com.pig4cloud.pigx.flow.task.constant.ProcessInstanceConstant; +import com.pig4cloud.pigx.flow.task.dto.Node; +import com.pig4cloud.pigx.flow.task.dto.NodeUser; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; + +/** + * 发起人自己 + * + * @author Huijun Zhao + * @description + * @date 2023-07-07 13:42 + */ +@Component(ProcessInstanceConstant.AssignedTypeClass.SELF + "AssignUserStrategy") +public class AssignUserSelfStrategyImpl implements AssignUserStrategy { + + @Override + public List handle(Node node, NodeUser rootUser, Map variables) { + return CollUtil.newArrayList(rootUser.getId()); + } + +} diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/service/CopyServiceTask.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/service/CopyServiceTask.java new file mode 100644 index 000000000..7c5fad91d --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/service/CopyServiceTask.java @@ -0,0 +1,91 @@ +package com.pig4cloud.pigx.flow.engine.service; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.spring.SpringUtil; +import com.alibaba.fastjson.JSON; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.task.api.feign.RemoteFlowTaskService; +import com.pig4cloud.pigx.flow.task.constant.NodeUserTypeEnum; +import com.pig4cloud.pigx.flow.task.dto.Node; +import com.pig4cloud.pigx.flow.task.dto.NodeUser; +import com.pig4cloud.pigx.flow.task.dto.ProcessCopyDto; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.delegate.JavaDelegate; +import org.flowable.engine.impl.persistence.entity.ExecutionEntityImpl; + +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 抄送任务处理器--java服务任务 + */ +public class CopyServiceTask implements JavaDelegate { + + /** + * 执行给定执行的任务。 + * @param execution 要处理的执行 + */ + @Override + public void execute(DelegateExecution execution) { + + ExecutionEntityImpl entity = (ExecutionEntityImpl) execution; + String nodeId = entity.getActivityId(); + String flowId = entity.getProcessDefinitionKey(); + + RemoteFlowTaskService remoteFlowTaskService = SpringUtil.getBean(RemoteFlowTaskService.class); + Node node = remoteFlowTaskService.queryNodeOriData(flowId, nodeId).getData(); + + // 获取指定人员 + List userDtoList = node.getNodeUserList(); + // 用户ID列表 + List userIdList = userDtoList.stream() + .filter(w -> StrUtil.equals(w.getType(), NodeUserTypeEnum.USER.getKey())) + .map(w -> Convert.toStr(w.getId())) + .collect(Collectors.toList()); + // 部门ID列表 + List deptIdList = userDtoList.stream() + .filter(w -> StrUtil.equals(w.getType(), NodeUserTypeEnum.DEPT.getKey())) + .map(w -> Convert.toStr(w.getId())) + .collect(Collectors.toList()); + + if (CollUtil.isNotEmpty(deptIdList)) { + + R> r = remoteFlowTaskService.queryUserIdListByDepIdList(deptIdList); + + List data = r.getData(); + if (CollUtil.isNotEmpty(data)) { + for (String datum : data) { + if (!userIdList.contains(datum)) { + userIdList.add(datum); + } + } + } + } + + // 获取发起人 + Object rootUserObj = execution.getVariable("root"); + NodeUser rootUser = JSON.parseArray(JSON.toJSONString(rootUserObj), NodeUser.class).get(0); + + Map variables = execution.getVariables(); + + for (String userIds : userIdList) { + // 发送抄送任务 + ProcessCopyDto processCopyDto = new ProcessCopyDto(); + processCopyDto.setNodeTime(new Date()); + processCopyDto.setStartUserId(rootUser.getId()); + processCopyDto.setFlowId(flowId); + processCopyDto.setProcessInstanceId(execution.getProcessInstanceId()); + processCopyDto.setNodeId(nodeId); + processCopyDto.setNodeName(entity.getActivityName()); + processCopyDto.setFormData(JSON.toJSONString(variables)); + processCopyDto.setUserId(Long.parseLong(userIds)); + remoteFlowTaskService.saveCC(processCopyDto); + } + + } + +} diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/service/packge-info.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/service/packge-info.java new file mode 100644 index 000000000..d749389d8 --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/service/packge-info.java @@ -0,0 +1,4 @@ +/* + * @author pigx archetype + */ +package com.pig4cloud.pigx.flow.engine.service; \ No newline at end of file diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/utils/FlowableUtils.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/utils/FlowableUtils.java new file mode 100644 index 000000000..66bd02153 --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/utils/FlowableUtils.java @@ -0,0 +1,664 @@ +package com.pig4cloud.pigx.flow.engine.utils; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.flowable.bpmn.model.*; +import org.flowable.engine.history.HistoricActivityInstance; +import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior; +import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior; + +import java.util.*; + +/** + * 流程引擎工具类封装 + * + * @author: linjinp + * @create: 2019-12-24 13:51 + **/ +public class FlowableUtils { + + public static final Logger logger = LogManager.getLogger(FlowableUtils.class); + + /** + * 根据节点获取入口连线集合 + * @param source 流程元素节点 + * @return 入口连线集合 + */ + public static List getElementIncomingFlows(FlowElement source) { + List sequenceFlows = null; + if (source instanceof Task) { + sequenceFlows = ((Task) source).getIncomingFlows(); + } + else if (source instanceof Gateway) { + sequenceFlows = ((Gateway) source).getIncomingFlows(); + } + else if (source instanceof SubProcess) { + sequenceFlows = ((SubProcess) source).getIncomingFlows(); + } + else if (source instanceof StartEvent) { + sequenceFlows = ((StartEvent) source).getIncomingFlows(); + } + else if (source instanceof EndEvent) { + sequenceFlows = ((EndEvent) source).getIncomingFlows(); + } + return sequenceFlows; + } + + /** + * 根据节点获取出口连线集合 + * @param source 流程元素节点 + * @return 出口连线集合 + */ + public static List getElementOutgoingFlows(FlowElement source) { + List sequenceFlows = null; + if (source instanceof Task) { + sequenceFlows = ((Task) source).getOutgoingFlows(); + } + else if (source instanceof Gateway) { + sequenceFlows = ((Gateway) source).getOutgoingFlows(); + } + else if (source instanceof SubProcess) { + sequenceFlows = ((SubProcess) source).getOutgoingFlows(); + } + else if (source instanceof StartEvent) { + sequenceFlows = ((StartEvent) source).getOutgoingFlows(); + } + else if (source instanceof EndEvent) { + sequenceFlows = ((EndEvent) source).getOutgoingFlows(); + } + return sequenceFlows; + } + + /** + * 递归获取流程定义所有的流程元素 + * @param flowElements 当前级别流程元素集合 + * @param allElements 用于存储的全部流程元素集合 + * @return 全部流程元素集合 + */ + public static Collection getAllElements(Collection flowElements, + Collection allElements) { + allElements = allElements == null ? new ArrayList<>() : allElements; + + for (FlowElement flowElement : flowElements) { + allElements.add(flowElement); + if (flowElement instanceof SubProcess) { + // 继续深入子流程,进一步获取子流程 + allElements = FlowableUtils.getAllElements(((SubProcess) flowElement).getFlowElements(), allElements); + } + } + return allElements; + } + + /** + * 从后向前递归获取父级用户任务节点 + * @param source 当前节点 + * @param hasSequenceFlow 已处理过的顺序流集合,避免循环 + * @param userTaskList 递归获取的用户任务节点集合 + * @return 用户任务节点集合 + */ + public static List iteratorFindParentUserTasks(FlowElement source, Set hasSequenceFlow, + List userTaskList) { + userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList; + hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; + + // 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代 + if (source instanceof StartEvent && source.getSubProcess() != null) { + userTaskList = iteratorFindParentUserTasks(source.getSubProcess(), hasSequenceFlow, userTaskList); + } + + // 根据类型,获取入口连线 + List sequenceFlows = getElementIncomingFlows(source); + + if (sequenceFlows != null) { + // 循环找到目标元素 + for (SequenceFlow sequenceFlow : sequenceFlows) { + // 如果发现连线重复,说明循环了,跳过这个循环 + if (hasSequenceFlow.contains(sequenceFlow.getId())) { + continue; + } + // 添加已经走过的连线 + hasSequenceFlow.add(sequenceFlow.getId()); + // 类型为用户节点,则新增父级节点 + if (sequenceFlow.getSourceFlowElement() instanceof UserTask) { + userTaskList.add((UserTask) sequenceFlow.getSourceFlowElement()); + continue; + } + // 类型为子流程,则添加子流程开始节点出口处相连的节点 + if (sequenceFlow.getSourceFlowElement() instanceof SubProcess) { + // 获取子流程用户任务节点 + List childUserTaskList = findChildProcessUserTasks( + (StartEvent) ((SubProcess) sequenceFlow.getSourceFlowElement()).getFlowElements() + .toArray()[0], + null, null); + // 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续 + if (childUserTaskList != null && childUserTaskList.size() > 0) { + userTaskList.addAll(childUserTaskList); + continue; + } + } + // 继续迭代 + // 注意:已经经过的节点与连线都应该用浅拷贝出来的对象 + // 比如分支:a->b->c与a->d->c,走完a->b->c后走另一个路线是,已经经过的节点应该不包含a->b->c路线的数据 + userTaskList = iteratorFindParentUserTasks(sequenceFlow.getSourceFlowElement(), + new HashSet<>(hasSequenceFlow), userTaskList); + } + } + return userTaskList; + } + + /** + * 根据正在运行的任务节点,迭代获取子级任务节点列表,向后找 + * @param source 起始节点 + * @param runActiveIdList 正在运行的任务 Key,用于校验任务节点是否是正在运行的节点 + * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 + * @param flowElementList 需要撤回的用户任务列表 + * @return + */ + public static List iteratorFindChildUserTasks(FlowElement source, List runActiveIdList, + Set hasSequenceFlow, List flowElementList) { + hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; + flowElementList = flowElementList == null ? new ArrayList<>() : flowElementList; + + // 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代 + if (source instanceof EndEvent && source.getSubProcess() != null) { + flowElementList = iteratorFindChildUserTasks(source.getSubProcess(), runActiveIdList, hasSequenceFlow, + flowElementList); + } + + // 根据类型,获取出口连线 + List sequenceFlows = getElementOutgoingFlows(source); + + if (sequenceFlows != null) { + // 循环找到目标元素 + for (SequenceFlow sequenceFlow : sequenceFlows) { + // 如果发现连线重复,说明循环了,跳过这个循环 + if (hasSequenceFlow.contains(sequenceFlow.getId())) { + continue; + } + // 添加已经走过的连线 + hasSequenceFlow.add(sequenceFlow.getId()); + // 如果为用户任务类型,或者为网关 + // 活动节点ID 在运行的任务中存在,添加 + if ((sequenceFlow.getTargetFlowElement() instanceof UserTask + || sequenceFlow.getTargetFlowElement() instanceof Gateway) + && runActiveIdList.contains((sequenceFlow.getTargetFlowElement()).getId())) { + flowElementList.add(sequenceFlow.getTargetFlowElement()); + continue; + } + // 如果节点为子流程节点情况,则从节点中的第一个节点开始获取 + if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) { + List childUserTaskList = iteratorFindChildUserTasks( + (FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements() + .toArray()[0]), + runActiveIdList, hasSequenceFlow, null); + // 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续 + if (childUserTaskList != null && childUserTaskList.size() > 0) { + flowElementList.addAll(childUserTaskList); + continue; + } + } + // 继续迭代 + // 注意:已经经过的节点与连线都应该用浅拷贝出来的对象 + // 比如分支:a->b->c与a->d->c,走完a->b->c后走另一个路线是,已经经过的节点应该不包含a->b->c路线的数据 + flowElementList = iteratorFindChildUserTasks(sequenceFlow.getTargetFlowElement(), runActiveIdList, + new HashSet<>(hasSequenceFlow), flowElementList); + } + } + return flowElementList; + } + + /** + * 迭代获取子流程用户任务节点 + * @param source 起始节点 + * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 + * @param userTaskList 需要撤回的用户任务列表 + * @return + */ + public static List findChildProcessUserTasks(FlowElement source, Set hasSequenceFlow, + List userTaskList) { + hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; + userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList; + + // 根据类型,获取出口连线 + List sequenceFlows = getElementOutgoingFlows(source); + + if (sequenceFlows != null) { + // 循环找到目标元素 + for (SequenceFlow sequenceFlow : sequenceFlows) { + // 如果发现连线重复,说明循环了,跳过这个循环 + if (hasSequenceFlow.contains(sequenceFlow.getId())) { + continue; + } + // 添加已经走过的连线 + hasSequenceFlow.add(sequenceFlow.getId()); + // 如果为用户任务类型,且任务节点的 Key 正在运行的任务中存在,添加 + if (sequenceFlow.getTargetFlowElement() instanceof UserTask) { + userTaskList.add((UserTask) sequenceFlow.getTargetFlowElement()); + continue; + } + // 如果节点为子流程节点情况,则从节点中的第一个节点开始获取 + if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) { + List childUserTaskList = findChildProcessUserTasks( + (FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements() + .toArray()[0]), + hasSequenceFlow, null); + // 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续 + if (childUserTaskList != null && childUserTaskList.size() > 0) { + userTaskList.addAll(childUserTaskList); + continue; + } + } + // 继续迭代 + // 注意:已经经过的节点与连线都应该用浅拷贝出来的对象 + // 比如分支:a->b->c与a->d->c,走完a->b->c后走另一个路线是,已经经过的节点应该不包含a->b->c路线的数据 + userTaskList = findChildProcessUserTasks(sequenceFlow.getTargetFlowElement(), + new HashSet<>(hasSequenceFlow), userTaskList); + } + } + return userTaskList; + } + + /** + * 从后向前寻路,获取所有脏线路上的点 + * @param source 起始节点 + * @param passRoads 已经经过的点集合 + * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 + * @param targets 目标脏线路终点 + * @param dirtyRoads 确定为脏数据的点,因为不需要重复,因此使用 set 存储 + * @return + */ + public static Set iteratorFindDirtyRoads(FlowElement source, List passRoads, + Set hasSequenceFlow, List targets, Set dirtyRoads) { + passRoads = passRoads == null ? new ArrayList<>() : passRoads; + dirtyRoads = dirtyRoads == null ? new HashSet<>() : dirtyRoads; + hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; + + // 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代 + if (source instanceof StartEvent && source.getSubProcess() != null) { + dirtyRoads = iteratorFindDirtyRoads(source.getSubProcess(), passRoads, hasSequenceFlow, targets, + dirtyRoads); + } + + // 根据类型,获取入口连线 + List sequenceFlows = getElementIncomingFlows(source); + + if (sequenceFlows != null) { + // 循环找到目标元素 + for (SequenceFlow sequenceFlow : sequenceFlows) { + // 如果发现连线重复,说明循环了,跳过这个循环 + if (hasSequenceFlow.contains(sequenceFlow.getId())) { + continue; + } + // 添加已经走过的连线 + hasSequenceFlow.add(sequenceFlow.getId()); + // 新增经过的路线 + passRoads.add(sequenceFlow.getSourceFlowElement().getId()); + // 如果此点为目标点,确定经过的路线为脏线路,添加点到脏线路中,然后找下个连线 + if (targets.contains(sequenceFlow.getSourceFlowElement().getId())) { + dirtyRoads.addAll(passRoads); + continue; + } + // 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代 + if (sequenceFlow.getSourceFlowElement() instanceof SubProcess) { + dirtyRoads = findChildProcessAllDirtyRoad( + (StartEvent) ((SubProcess) sequenceFlow.getSourceFlowElement()).getFlowElements() + .toArray()[0], + null, dirtyRoads); + // 是否存在子流程上,true 是,false 否 + Boolean isInChildProcess = dirtyTargetInChildProcess( + (StartEvent) ((SubProcess) sequenceFlow.getSourceFlowElement()).getFlowElements() + .toArray()[0], + null, targets, null); + if (isInChildProcess) { + // 已在子流程上找到,该路线结束 + continue; + } + } + // 继续迭代 + // 注意:已经经过的节点与连线都应该用浅拷贝出来的对象 + // 比如分支:a->b->c与a->d->c,走完a->b->c后走另一个路线是,已经经过的节点应该不包含a->b->c路线的数据 + dirtyRoads = iteratorFindDirtyRoads(sequenceFlow.getSourceFlowElement(), new ArrayList<>(passRoads), + new HashSet<>(hasSequenceFlow), targets, dirtyRoads); + } + } + return dirtyRoads; + } + + /** + * 迭代获取子流程脏路线 说明,假如回退的点就是子流程,那么也肯定会回退到子流程最初的用户任务节点,因此子流程中的节点全是脏路线 + * @param source 起始节点 + * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 + * @param dirtyRoads 确定为脏数据的点,因为不需要重复,因此使用 set 存储 + * @return + */ + public static Set findChildProcessAllDirtyRoad(FlowElement source, Set hasSequenceFlow, + Set dirtyRoads) { + hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; + dirtyRoads = dirtyRoads == null ? new HashSet<>() : dirtyRoads; + + // 根据类型,获取出口连线 + List sequenceFlows = getElementOutgoingFlows(source); + + if (sequenceFlows != null) { + // 循环找到目标元素 + for (SequenceFlow sequenceFlow : sequenceFlows) { + // 如果发现连线重复,说明循环了,跳过这个循环 + if (hasSequenceFlow.contains(sequenceFlow.getId())) { + continue; + } + // 添加已经走过的连线 + hasSequenceFlow.add(sequenceFlow.getId()); + // 添加脏路线 + dirtyRoads.add(sequenceFlow.getTargetFlowElement().getId()); + // 如果节点为子流程节点情况,则从节点中的第一个节点开始获取 + if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) { + dirtyRoads = findChildProcessAllDirtyRoad( + (FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements() + .toArray()[0]), + hasSequenceFlow, dirtyRoads); + } + // 继续迭代 + // 注意:已经经过的节点与连线都应该用浅拷贝出来的对象 + // 比如分支:a->b->c与a->d->c,走完a->b->c后走另一个路线是,已经经过的节点应该不包含a->b->c路线的数据 + dirtyRoads = findChildProcessAllDirtyRoad(sequenceFlow.getTargetFlowElement(), + new HashSet<>(hasSequenceFlow), dirtyRoads); + } + } + return dirtyRoads; + } + + /** + * 判断脏路线结束节点是否在子流程上 + * @param source 起始节点 + * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 + * @param targets 判断脏路线节点是否存在子流程上,只要存在一个,说明脏路线只到子流程为止 + * @param inChildProcess 是否存在子流程上,true 是,false 否 + * @return + */ + public static Boolean dirtyTargetInChildProcess(FlowElement source, Set hasSequenceFlow, + List targets, Boolean inChildProcess) { + hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; + inChildProcess = inChildProcess == null ? false : inChildProcess; + + // 根据类型,获取出口连线 + List sequenceFlows = getElementOutgoingFlows(source); + + if (sequenceFlows != null && !inChildProcess) { + // 循环找到目标元素 + for (SequenceFlow sequenceFlow : sequenceFlows) { + // 如果发现连线重复,说明循环了,跳过这个循环 + if (hasSequenceFlow.contains(sequenceFlow.getId())) { + continue; + } + // 添加已经走过的连线 + hasSequenceFlow.add(sequenceFlow.getId()); + // 如果发现目标点在子流程上存在,说明只到子流程为止 + if (targets.contains(sequenceFlow.getTargetFlowElement().getId())) { + inChildProcess = true; + break; + } + // 如果节点为子流程节点情况,则从节点中的第一个节点开始获取 + if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) { + inChildProcess = dirtyTargetInChildProcess( + (FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements() + .toArray()[0]), + hasSequenceFlow, targets, inChildProcess); + } + // 继续迭代 + // 注意:已经经过的节点与连线都应该用浅拷贝出来的对象 + // 比如分支:a->b->c与a->d->c,走完a->b->c后走另一个路线是,已经经过的节点应该不包含a->b->c路线的数据 + inChildProcess = dirtyTargetInChildProcess(sequenceFlow.getTargetFlowElement(), + new HashSet<>(hasSequenceFlow), targets, inChildProcess); + } + } + return inChildProcess; + } + + /** + * 迭代从后向前扫描,判断目标节点相对于当前节点是否是串行 不存在直接回退到子流程中的情况,但存在从子流程出去到父流程情况 + * @param source 起始节点 + * @param isSequential 是否串行 + * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 + * @param targetKsy 目标节点 + * @return + */ + public static Boolean iteratorCheckSequentialReferTarget(FlowElement source, String targetKsy, + Set hasSequenceFlow, Boolean isSequential) { + isSequential = isSequential == null ? true : isSequential; + hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; + + // 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代 + if (source instanceof StartEvent && source.getSubProcess() != null) { + isSequential = iteratorCheckSequentialReferTarget(source.getSubProcess(), targetKsy, hasSequenceFlow, + isSequential); + } + + // 根据类型,获取入口连线 + List sequenceFlows = getElementIncomingFlows(source); + + if (sequenceFlows != null) { + // 循环找到目标元素 + for (SequenceFlow sequenceFlow : sequenceFlows) { + // 如果发现连线重复,说明循环了,跳过这个循环 + if (hasSequenceFlow.contains(sequenceFlow.getId())) { + continue; + } + // 添加已经走过的连线 + hasSequenceFlow.add(sequenceFlow.getId()); + // 如果目标节点已被判断为并行,后面都不需要执行,直接返回 + if (isSequential == false) { + break; + } + // 这条线路存在目标节点,这条线路完成,进入下个线路 + if (targetKsy.equals(sequenceFlow.getSourceFlowElement().getId())) { + continue; + } + if (sequenceFlow.getSourceFlowElement() instanceof StartEvent) { + isSequential = false; + break; + } + // 否则就继续迭代 + // 注意:已经经过的节点与连线都应该用浅拷贝出来的对象 + // 比如分支:a->b->c与a->d->c,走完a->b->c后走另一个路线是,已经经过的节点应该不包含a->b->c路线的数据 + isSequential = iteratorCheckSequentialReferTarget(sequenceFlow.getSourceFlowElement(), targetKsy, + new HashSet<>(hasSequenceFlow), isSequential); + } + } + return isSequential; + } + + /** + * 从后向前寻路,获取到达节点的所有路线 不存在直接回退到子流程,但是存在回退到父级流程的情况 + * @param source 起始节点 + * @param passRoads 已经经过的点集合 + * @param roads 路线 + * @return + */ + public static List> findRoad(FlowElement source, List passRoads, + Set hasSequenceFlow, List> roads) { + passRoads = passRoads == null ? new ArrayList<>() : passRoads; + roads = roads == null ? new ArrayList<>() : roads; + hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; + + // 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代 + if (source instanceof StartEvent && source.getSubProcess() != null) { + roads = findRoad(source.getSubProcess(), passRoads, hasSequenceFlow, roads); + } + + // 根据类型,获取入口连线 + List sequenceFlows = getElementIncomingFlows(source); + + if (sequenceFlows != null && sequenceFlows.size() != 0) { + for (SequenceFlow sequenceFlow : sequenceFlows) { + // 如果发现连线重复,说明循环了,跳过这个循环 + if (hasSequenceFlow.contains(sequenceFlow.getId())) { + continue; + } + // 添加已经走过的连线 + hasSequenceFlow.add(sequenceFlow.getId()); + // 添加经过路线 + if (sequenceFlow.getSourceFlowElement() instanceof UserTask) { + passRoads.add((UserTask) sequenceFlow.getSourceFlowElement()); + } + // 继续迭代 + // 注意:已经经过的节点与连线都应该用浅拷贝出来的对象 + // 比如分支:a->b->c与a->d->c,走完a->b->c后走另一个路线是,已经经过的节点应该不包含a->b->c路线的数据 + roads = findRoad(sequenceFlow.getSourceFlowElement(), new ArrayList<>(passRoads), + new HashSet<>(hasSequenceFlow), roads); + } + } + else { + // 添加路线 + roads.add(passRoads); + } + return roads; + } + + /** + * 历史节点数据清洗,清洗掉又回滚导致的脏数据 + * @param allElements 全部节点信息 + * @param historicActivityIdList 历史任务实例信息,数据采用开始时间升序 + * @return + */ + public static List historicTaskInstanceClean(Collection allElements, + List historicActivityIdList) { + // 会签节点收集 + List multiTask = new ArrayList<>(); + allElements.forEach(flowElement -> { + if (flowElement instanceof UserTask) { + // 如果该节点的行为为会签行为,说明该节点为会签节点 + if (((UserTask) flowElement).getBehavior() instanceof ParallelMultiInstanceBehavior + || ((UserTask) flowElement).getBehavior() instanceof SequentialMultiInstanceBehavior) { + multiTask.add(flowElement.getId()); + } + } + }); + // 循环放入栈,栈 LIFO:后进先出 + Stack stack = new Stack<>(); + historicActivityIdList.forEach(item -> stack.push(item)); + // 清洗后的历史任务实例 + List lastHistoricTaskInstanceList = new ArrayList<>(); + // 网关存在可能只走了部分分支情况,且还存在跳转废弃数据以及其他分支数据的干扰,因此需要对历史节点数据进行清洗 + // 临时用户任务 key + StringBuilder userTaskKey = null; + // 临时被删掉的任务 key,存在并行情况 + List deleteKeyList = new ArrayList<>(); + // 临时脏数据线路 + List> dirtyDataLineList = new ArrayList<>(); + // 由某个点跳到会签点,此时出现多个会签实例对应 1 个跳转情况,需要把这些连续脏数据都找到 + // 会签特殊处理下标 + int multiIndex = -1; + // 会签特殊处理 key + StringBuilder multiKey = null; + // 会签特殊处理操作标识 + boolean multiOpera = false; + while (!stack.empty()) { + // 从这里开始 userTaskKey 都还是上个栈的 key + // 是否是脏数据线路上的点 + final boolean[] isDirtyData = { false }; + for (Set oldDirtyDataLine : dirtyDataLineList) { + if (oldDirtyDataLine.contains(stack.peek().getActivityId())) { + isDirtyData[0] = true; + } + } + // 删除原因不为空,说明从这条数据开始回跳或者回退的 + // MI_END:会签完成后,其他未签到节点的删除原因,不在处理范围内 + if (stack.peek().getDeleteReason() != null && !stack.peek().getDeleteReason().equals("MI_END")) { + // 可以理解为脏线路起点 + String dirtyPoint = ""; + if (stack.peek().getDeleteReason().indexOf("Change activity to ") >= 0) { + dirtyPoint = stack.peek().getDeleteReason().replace("Change activity to ", ""); + } + // 会签回退删除原因有点不同 + if (stack.peek().getDeleteReason().indexOf("Change parent activity to ") >= 0) { + dirtyPoint = stack.peek().getDeleteReason().replace("Change parent activity to ", ""); + } + FlowElement dirtyTask = null; + // 获取变更节点的对应的入口处连线 + // 如果是网关并行回退情况,会变成两条脏数据路线,效果一样 + for (FlowElement flowElement : allElements) { + if (flowElement.getId().equals(stack.peek().getActivityId())) { + dirtyTask = flowElement; + } + } + // 获取脏数据线路 + Set dirtyDataLine = FlowableUtils.iteratorFindDirtyRoads(dirtyTask, null, null, + Arrays.asList(dirtyPoint.split(",")), null); + // 自己本身也是脏线路上的点,加进去 + dirtyDataLine.add(stack.peek().getActivityId()); + logger.info(stack.peek().getActivityId() + "点脏路线集合:" + dirtyDataLine); + // 是全新的需要添加的脏线路 + boolean isNewDirtyData = true; + for (int i = 0; i < dirtyDataLineList.size(); i++) { + // 如果发现他的上个节点在脏线路内,说明这个点可能是并行的节点,或者连续驳回 + // 这时,都以之前的脏线路节点为标准,只需合并脏线路即可,也就是路线补全 + if (dirtyDataLineList.get(i).contains(userTaskKey.toString())) { + isNewDirtyData = false; + dirtyDataLineList.get(i).addAll(dirtyDataLine); + } + } + // 已确定时全新的脏线路 + if (isNewDirtyData) { + // deleteKey 单一路线驳回到并行,这种同时生成多个新实例记录情况,这时 deleteKey 其实是由多个值组成 + // 按照逻辑,回退后立刻生成的实例记录就是回退的记录 + // 至于驳回所生成的 Key,直接从删除原因中获取,因为存在驳回到并行的情况 + deleteKeyList.add(dirtyPoint + ","); + dirtyDataLineList.add(dirtyDataLine); + } + // 添加后,现在这个点变成脏线路上的点了 + isDirtyData[0] = true; + } + // 如果不是脏线路上的点,说明是有效数据,添加历史实例 Key + if (!isDirtyData[0]) { + lastHistoricTaskInstanceList.add(stack.peek().getActivityId()); + } + // 校验脏线路是否结束 + for (int i = 0; i < deleteKeyList.size(); i++) { + // 如果发现脏数据属于会签,记录下下标与对应 Key,以备后续比对,会签脏数据范畴开始 + if (multiKey == null && multiTask.contains(stack.peek().getActivityId()) + && deleteKeyList.get(i).contains(stack.peek().getActivityId())) { + multiIndex = i; + multiKey = new StringBuilder(stack.peek().getActivityId()); + } + // 会签脏数据处理,节点退回会签清空 + // 如果在会签脏数据范畴中发现 Key改变,说明会签脏数据在上个节点就结束了,可以把会签脏数据删掉 + if (multiKey != null && !multiKey.toString().equals(stack.peek().getActivityId())) { + deleteKeyList.set(multiIndex, + deleteKeyList.get(multiIndex).replace(stack.peek().getActivityId() + ",", "")); + multiKey = null; + // 结束进行下校验删除 + multiOpera = true; + } + // 其他脏数据处理 + // 发现该路线最后一条脏数据,说明这条脏数据线路处理完了,删除脏数据信息 + // 脏数据产生的新实例中是否包含这条数据 + if (multiKey == null && deleteKeyList.get(i).contains(stack.peek().getActivityId())) { + // 删除匹配到的部分 + deleteKeyList.set(i, deleteKeyList.get(i).replace(stack.peek().getActivityId() + ",", "")); + } + // 如果每组中的元素都以匹配过,说明脏数据结束 + if ("".equals(deleteKeyList.get(i))) { + // 同时删除脏数据 + deleteKeyList.remove(i); + dirtyDataLineList.remove(i); + break; + } + } + // 会签数据处理需要在循环外处理,否则可能导致溢出 + // 会签的数据肯定是之前放进去的所以理论上不会溢出,但还是校验下 + if (multiOpera && deleteKeyList.size() > multiIndex && "".equals(deleteKeyList.get(multiIndex))) { + // 同时删除脏数据 + deleteKeyList.remove(multiIndex); + dirtyDataLineList.remove(multiIndex); + multiIndex = -1; + multiOpera = false; + } + // pop() 方法与 peek() 方法不同,在返回值的同时,会把值从栈中移除 + // 保存新的 userTaskKey 在下个循环中使用 + userTaskKey = new StringBuilder(stack.pop().getActivityId()); + } + logger.info("清洗后的历史节点数据:" + lastHistoricTaskInstanceList); + return lastHistoricTaskInstanceList; + } + +} diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/utils/ModelUtil.java b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/utils/ModelUtil.java new file mode 100644 index 000000000..60256e3b3 --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/java/com/pig4cloud/pigx/flow/engine/utils/ModelUtil.java @@ -0,0 +1,595 @@ +package com.pig4cloud.pigx.flow.engine.utils; + +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.RandomUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.spring.SpringUtil; +import cn.hutool.json.JSONUtil; +import com.pig4cloud.pigx.flow.engine.expression.condition.NodeExpressionStrategyFactory; +import com.pig4cloud.pigx.flow.engine.listeners.ApprovalCreateListener; +import com.pig4cloud.pigx.flow.engine.listeners.FlowProcessEventListener; +import com.pig4cloud.pigx.flow.engine.service.CopyServiceTask; +import com.pig4cloud.pigx.flow.task.api.feign.RemoteFlowTaskService; +import com.pig4cloud.pigx.flow.task.constant.NodeTypeEnum; +import com.pig4cloud.pigx.flow.task.constant.ProcessInstanceConstant; +import com.pig4cloud.pigx.flow.task.dto.Node; +import com.pig4cloud.pigx.flow.task.dto.ProcessNodeDataDto; +import com.pig4cloud.pigx.flow.task.utils.NodeUtil; +import lombok.extern.slf4j.Slf4j; +import org.flowable.bpmn.model.Process; +import org.flowable.bpmn.model.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +/** + * 模型工具类 处理模型构建相关的 + */ +@Slf4j +public class ModelUtil { + + /** + * 构建BPMN流程模型 + * @param nodeDto 前端传过来的节点数据 + * @param processName 流程名称 + * @param flowId 流程定义ID + * @return 流程模型对象 + */ + public static BpmnModel buildBpmnModel(Node nodeDto, String processName, String flowId) { + BpmnModel bpmnModel = new BpmnModel(); + bpmnModel.setTargetNamespace("MODEL"); + + Process process = new Process(); + process.setId(flowId); + process.setName(processName); + + // 流程监听器 + ArrayList eventListeners = new ArrayList<>(); + + { + // 流程实例监听器 + EventListener eventListener = new EventListener(); + + eventListener.setImplementationType("class"); + eventListener.setImplementation(FlowProcessEventListener.class.getCanonicalName()); + + eventListeners.add(eventListener); + + } + process.setEventListeners(eventListeners); + + // 构建结束节点 + + Node endNodeDto = new Node(); + endNodeDto.setId(StrUtil.format("end")); + endNodeDto.setHeadId(endNodeDto.getId()); + endNodeDto.setName("endNode"); + + // 构建节点 + EndEvent endEvent = buildEndNode(endNodeDto, false); + process.addFlowElement(endEvent); + // 创建所有的节点 + buildAllNode(process, nodeDto, flowId); + // 创建所有的内部节点连接线 + buildAllNodeInnerSequence(process, nodeDto, flowId); + // 创建节点间连线 + buildAllNodeOuterSequence(process, nodeDto, endNodeDto); + + bpmnModel.addProcess(process); + return bpmnModel; + } + + /** + * 递归构建所有节点 + * @param process 流程对象 + * @param nodeDto 当前节点数据 + * @param flowId 流程定义ID + */ + public static void buildAllNode(Process process, Node nodeDto, String flowId) { + if (!NodeUtil.isNode(nodeDto)) { + return; + } + List flowElementList = buildNode(nodeDto, flowId); + for (FlowElement flowElement : flowElementList) { + if (process.getFlowElement(flowElement.getId()) == null) { + process.addFlowElement(flowElement); + } + } + + // 子节点 + Node children = nodeDto.getChildren(); + if (Objects.equals(nodeDto.getType(), NodeTypeEnum.EXCLUSIVE_GATEWAY.getValue()) + || Objects.equals(nodeDto.getType(), NodeTypeEnum.PARALLEL_GATEWAY.getValue())) { + + // 条件分支 + List branchs = nodeDto.getConditionNodes(); + for (Node branch : branchs) { + buildAllNode(process, branch.getChildren(), flowId); + + } + if (NodeUtil.isNode(children)) { + buildAllNode(process, children, flowId); + } + + } + else { + + if (NodeUtil.isNode(children)) { + buildAllNode(process, children, flowId); + } + } + + } + + /** + * 递归构建节点内部的顺序流 + * @param process 流程对象 + * @param nodeDto 当前节点数据 + * @param flowId 流程定义ID + */ + public static void buildAllNodeInnerSequence(Process process, Node nodeDto, String flowId) { + if (!NodeUtil.isNode(nodeDto)) { + return; + } + // 画内部线 + List flowList = buildInnerSequenceFlow(nodeDto, flowId); + for (SequenceFlow sequenceFlow : flowList) { + process.addFlowElement(sequenceFlow); + } + + // 子节点 + Node children = nodeDto.getChildren(); + if (nodeDto.getType() == NodeTypeEnum.EXCLUSIVE_GATEWAY.getValue().intValue() + || nodeDto.getType() == NodeTypeEnum.PARALLEL_GATEWAY.getValue().intValue()) { + // 条件分支 + List branchs = nodeDto.getConditionNodes(); + for (Node branch : branchs) { + buildAllNodeInnerSequence(process, branch.getChildren(), flowId); + + } + if (NodeUtil.isNode(children)) { + buildAllNodeInnerSequence(process, children, flowId); + } + + } + else { + + if (NodeUtil.isNode(children)) { + buildAllNodeInnerSequence(process, children, flowId); + } + } + + } + + /** + * 递归构建节点之间的顺序流 + * @param process 流程对象 + * @param nodeDto 当前节点数据 + * @param nextNodeDto 下一个节点数据 + */ + public static void buildAllNodeOuterSequence(Process process, Node nodeDto, Node nextNodeDto) { + if (!NodeUtil.isNode(nodeDto)) { + return; + } + + // 子节点 + Node children = nodeDto.getChildren(); + if (nodeDto.getType() == NodeTypeEnum.EXCLUSIVE_GATEWAY.getValue().intValue() + || nodeDto.getType() == NodeTypeEnum.PARALLEL_GATEWAY.getValue().intValue()) { + // 条件分支 + List branchs = nodeDto.getConditionNodes(); + int ord = 1; + int size = branchs.size(); + for (Node branch : branchs) { + buildAllNodeOuterSequence(process, branch.getChildren(), + NodeUtil.isNode(children) ? children : nextNodeDto); + + String expression = null; + + if (nodeDto.getType() == NodeTypeEnum.EXCLUSIVE_GATEWAY.getValue().intValue()) { + if (ord == size) { + expression = NodeExpressionStrategyFactory.handleDefaultBranch(branchs); + } + else { + expression = NodeExpressionStrategyFactory.handle(branch); + } + + } + + // 添加连线 + if (!NodeUtil.isNode(branch.getChildren())) { + // 当前分支 没有其他节点了 所有就是网关和网关后面节点直接连线 + List sequenceFlowList = buildSequenceFlow( + NodeUtil.isNode(children) ? children : nextNodeDto, nodeDto, expression); + for (SequenceFlow sequenceFlow : sequenceFlowList) { + process.addFlowElement(sequenceFlow); + } + } + else { + // 当前节点 就是网关和第一个节点(非EMPTY节点)连线 + List sequenceFlowList = buildSequenceFlow(branch.getChildren(), nodeDto, expression); + for (SequenceFlow sequenceFlow : sequenceFlowList) { + process.addFlowElement(sequenceFlow); + } + } + ord++; + + } + if (NodeUtil.isNode(children)) { + buildAllNodeOuterSequence(process, children, nextNodeDto); + } + + } + else { + // 添加连线 + List sequenceFlowList = buildSequenceFlow(children, nodeDto, ""); + for (SequenceFlow sequenceFlow : sequenceFlowList) { + process.addFlowElement(sequenceFlow); + } + if (NodeUtil.isNode(children)) { + buildAllNodeOuterSequence(process, children, nextNodeDto); + } + else { + List sequenceFlowList1 = buildSequenceFlow(nextNodeDto, nodeDto, ""); + for (SequenceFlow sequenceFlow : sequenceFlowList1) { + process.addFlowElement(sequenceFlow); + } + } + } + + } + + /** + * 构建单个节点对象 + * @param node 节点数据 + * @param flowId 流程定义ID + * @return 流程元素列表 + */ + private static List buildNode(Node node, String flowId) { + List flowElementList = new ArrayList<>(); + + if (!NodeUtil.isNode(node)) { + return flowElementList; + } + + // 设置节点的连线头节点 + node.setHeadId(node.getId()); + // 设置节点的连线尾节点 + node.setTailId(node.getId()); + node.setName(StrUtil.format("{}[{}]", node.getName(), RandomUtil.randomNumbers(5))); + + // 存储节点数据 + RemoteFlowTaskService remoteFlowTaskService = SpringUtil.getBean(RemoteFlowTaskService.class); + ProcessNodeDataDto processNodeDataDto = new ProcessNodeDataDto(); + processNodeDataDto.setFlowId(flowId); + processNodeDataDto.setNodeId(node.getId()); + processNodeDataDto.setData(JSONUtil.toJsonStr(node)); + remoteFlowTaskService.saveNodeOriData(processNodeDataDto); + + // 开始 + if (node.getType() == NodeTypeEnum.ROOT.getValue().intValue()) { + flowElementList.addAll(buildStartNode(node)); + } + + // 审批 + if (node.getType() == NodeTypeEnum.APPROVAL.getValue().intValue()) { + + flowElementList.addAll(buildApproveNode(node)); + } + + // 抄送 + if (node.getType() == NodeTypeEnum.CC.getValue().intValue()) { + + flowElementList.add(buildCCNode(node)); + } + // 条件分支 + if (node.getType() == NodeTypeEnum.EXCLUSIVE_GATEWAY.getValue().intValue()) { + + flowElementList.add(buildExclusiveGatewayNode(node)); + } + // 并行分支 + if (node.getType() == NodeTypeEnum.PARALLEL_GATEWAY.getValue().intValue()) { + + flowElementList.addAll(buildParallelGatewayNode(node)); + } + return flowElementList; + } + + /** + * 构建开始节点 添加一个自动完成任务的用户任务节点 + * @param node 前端传输节点 + * @return + */ + private static List buildStartNode(Node node) { + + StartEvent startEvent = new StartEvent(); + startEvent.setId(node.getId()); + startEvent.setName(node.getName()); + + List flowElementList = new ArrayList<>(); + flowElementList.add(startEvent); + + return flowElementList; + } + + /** + * 构建审批节点 + * @param node + * @return + */ + private static List buildApproveNode(Node node) { + List flowElementList = new ArrayList<>(); + + node.setTailId(StrUtil.format("approve_gateway_{}", node.getId())); + + // 创建了任务执行监听器 + // 先执行指派人 后创建 + // https://tkjohn.github.io/flowable-userguide/#eventDispatcher + FlowableListener createListener = new FlowableListener(); + createListener.setImplementation(ApprovalCreateListener.class.getCanonicalName()); + createListener.setImplementationType("class"); + createListener.setEvent("create"); + + UserTask userTask = buildUserTask(node, createListener); + flowElementList.add(userTask); + + Node exclusiveNode = new Node(); + exclusiveNode.setId(StrUtil.format("approve_gateway_{}", node.getId())); + exclusiveNode.setName("审批-排他网关"); + flowElementList.add(buildExclusiveGatewayNode(exclusiveNode)); + // 创建结束节点 + + Node endNode = new Node(); + endNode.setId(StrUtil.format("approve_end_{}", node.getId())); + endNode.setName("审批-结束节点"); + EndEvent endEvent = buildEndNode(endNode, false); + flowElementList.add(endEvent); + + { + + // 执行人处理 + + String inputDataItem = "${multiInstanceHandler.resolveAssignee(execution)}"; + + // 串行 + + boolean isSequential = true; + + Integer multipleMode = node.getMultipleMode(); + // 多人 + if ((multipleMode == ProcessInstanceConstant.MULTIPLE_MODE_AL_SAME)) { + // 并行会签 + isSequential = false; + } + // 串行会签 + if ((multipleMode == ProcessInstanceConstant.MULTIPLE_MODE_ONE)) { + + // 或签 + isSequential = false; + } + + MultiInstanceLoopCharacteristics loopCharacteristics = new MultiInstanceLoopCharacteristics(); + loopCharacteristics.setSequential(isSequential); + loopCharacteristics.setInputDataItem(inputDataItem); + loopCharacteristics.setElementVariable(StrUtil.format("{}_assignee_temp", node.getId())); + + loopCharacteristics.setCompletionCondition("${multiInstanceHandler.completionCondition(execution)}"); + + userTask.setLoopCharacteristics(loopCharacteristics); + String format = StrUtil.format("${{}_assignee_temp}", node.getId()); + userTask.setAssignee(format); + + } + return flowElementList; + } + + /** + * 创建用户任务 + * @param node 前端传输节点 + * @return + */ + private static UserTask buildUserTask(Node node, FlowableListener... flowableListeners) { + UserTask userTask = new UserTask(); + userTask.setId(node.getId()); + userTask.setName(node.getName()); + + if (flowableListeners != null) { + List taskListeners = new ArrayList<>(); + Collections.addAll(taskListeners, flowableListeners); + userTask.setTaskListeners(taskListeners); + } + + return userTask; + } + + /** + * 构建排他网关 + * @param node + * @return + */ + private static FlowElement buildExclusiveGatewayNode(Node node) { + ExclusiveGateway exclusiveGateway = new ExclusiveGateway(); + exclusiveGateway.setId(node.getId()); + exclusiveGateway.setName(node.getName()); + return exclusiveGateway; + + } + + /** + * 构建并行网关 + * @param node + * @return + */ + private static List buildParallelGatewayNode(Node node) { + // node.setTailId(StrUtil.format("{}_merge_gateway", node.getId())); + + List flowElementList = new ArrayList<>(); + + ParallelGateway inclusiveGateway = new ParallelGateway(); + inclusiveGateway.setId(node.getId()); + inclusiveGateway.setName(node.getName()); + flowElementList.add(inclusiveGateway); + + // 合并网关 + ParallelGateway parallelGateway = new ParallelGateway(); + parallelGateway.setId(StrUtil.format("{}_merge_gateway", node.getId())); + parallelGateway.setName(StrUtil.format("{}_合并网关", node.getName())); + flowElementList.add(parallelGateway); + + return flowElementList; + } + + /** + * 构建结束节点 + * @param node 前端传输节点 + * @param terminateAll + * @return + */ + private static EndEvent buildEndNode(Node node, boolean terminateAll) { + EndEvent endEvent = new EndEvent(); + endEvent.setId(node.getId()); + endEvent.setName(node.getName()); + + List definitionList = new ArrayList<>(); + TerminateEventDefinition definition = new TerminateEventDefinition(); + definition.setTerminateAll(terminateAll); + definitionList.add(definition); + endEvent.setEventDefinitions(definitionList); + + return endEvent; + } + + /** + * 创建连接线 + * @param node 子级节点 + * @param parentNode 父级节点 + * @param expression + * @return 所有连接线 + */ + private static List buildSequenceFlow(Node node, Node parentNode, String expression) { + List sequenceFlowList = new ArrayList<>(); + // 没有子级了 + if (!NodeUtil.isNode(node)) { + return sequenceFlowList; + } + + String pid = parentNode.getId(); + + if (StrUtil.hasBlank(pid, node.getId())) { + return sequenceFlowList; + } + + SequenceFlow sequenceFlow = buildSingleSequenceFlow(parentNode.getTailId(), node.getHeadId(), expression); + sequenceFlowList.add(sequenceFlow); + + return sequenceFlowList; + } + + /** + * 生成扩展数据 + * @param key + * @param val + * @return + */ + public static ExtensionAttribute generateExtensionAttribute(String key, String val) { + ExtensionAttribute ea = new ExtensionAttribute(); + + ea.setName(key); + ea.setValue(val); + return ea; + } + + /** + * 创建抄送节点 + * @param node + * @return + */ + private static FlowElement buildCCNode(Node node) { + + ServiceTask serviceTask = new ServiceTask(); + serviceTask.setId(node.getId()); + serviceTask.setName(node.getName()); + serviceTask.setImplementationType("class"); + serviceTask.setImplementation(CopyServiceTask.class.getCanonicalName()); + return serviceTask; + } + + /** + * 创建连接线 + * @param node 父级节点 + * @param flowId + * @return 所有连接线 + */ + private static List buildInnerSequenceFlow(Node node, String flowId) { + List sequenceFlowList = new ArrayList<>(); + + if (!NodeUtil.isNode(node)) { + return sequenceFlowList; + } + + String nodeId = node.getId(); + if (StrUtil.hasBlank(nodeId)) { + return sequenceFlowList; + } + boolean parentIsGateway = false; + Node prevNode = null; + if (StrUtil.isNotBlank(node.getParentId())) { + // 判断父级是否是包容或者并行网关 + RemoteFlowTaskService remoteFlowTaskService = SpringUtil.getBean(RemoteFlowTaskService.class); + prevNode = remoteFlowTaskService.queryNodeOriData(flowId, node.getParentId()).getData(); + if (prevNode != null) { + parentIsGateway = (Objects.equals(prevNode.getType(), NodeTypeEnum.PARALLEL_GATEWAY.getValue())); + + } + + } + + if (parentIsGateway) { + String headId = node.getHeadId(); + node.setHeadId(StrUtil.format("{}_merge_gateway", prevNode.getId())); + { + SequenceFlow sequenceFlow = buildSingleSequenceFlow(node.getHeadId(), headId, "${12==12}"); + sequenceFlowList.add(sequenceFlow); + } + + } + + if (node.getType() == NodeTypeEnum.APPROVAL.getValue().intValue()) { + + String gatewayId = StrUtil.format("approve_gateway_{}", nodeId); + String endId = StrUtil.format("approve_end_{}", nodeId); + + { + SequenceFlow sequenceFlow = buildSingleSequenceFlow(nodeId, gatewayId, "${12==12}"); + sequenceFlowList.add(sequenceFlow); + } + + { + SequenceFlow sequenceFlow = buildSingleSequenceFlow(gatewayId, endId, + StrUtil.format("${!" + "{}_approve_condition}", nodeId)); + sequenceFlowList.add(sequenceFlow); + } + + } + + return sequenceFlowList; + } + + /** + * 创建单个连接线 + * @param pId 父级id + * @param childId 子级id + * @param expression 表达式 + * @return + */ + private static SequenceFlow buildSingleSequenceFlow(String pId, String childId, String expression) { + SequenceFlow sequenceFlow = new SequenceFlow(pId, childId); + sequenceFlow.setConditionExpression(expression); + sequenceFlow.setName(StrUtil.format("{}|{}", pId, childId)); + sequenceFlow.setId(StrUtil.format("sq-id-{}-{}", IdUtil.fastSimpleUUID(), RandomUtil.randomInt(1, 10000000))); + return sequenceFlow; + } + +} diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/resources/application.yml b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/resources/application.yml new file mode 100644 index 000000000..409ccb3af --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/resources/application.yml @@ -0,0 +1,25 @@ +server: + port: 5020 + +spring: + application: + name: @artifactId@ + cloud: + nacos: + username: @nacos.username@ + password: @nacos.password@ + discovery: + server-addr: ${NACOS_HOST:pigx-register}:${NACOS_PORT:8848} + config: + server-addr: ${spring.cloud.nacos.discovery.server-addr} + config: + import: + - optional:nacos:application-@profiles.active@.yml + - optional:nacos:${spring.application.name}-@profiles.active@.yml + datasource: + type: com.alibaba.druid.pool.DruidDataSource + druid: + driver-class-name: com.mysql.cj.jdbc.Driver + username: ${MYSQL_USER:root} + password: ${MYSQL_PWD:root} + url: jdbc:mysql://${MYSQL_HOST:pigx-mysql}:${MYSQL_PORT:3306}/${MYSQL_DB:simple_flow}?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&allowMultiQueries=true&nullCatalogMeansCurrent=true diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/resources/logback-spring.xml b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/resources/logback-spring.xml new file mode 100644 index 000000000..0cd6c2983 --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/src/main/resources/logback-spring.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + ${CONSOLE_LOG_PATTERN} + + + + + + ${log.path}/debug.log + + ${log.path}/%d{yyyy-MM, aux}/debug.%d{yyyy-MM-dd}.%i.log.gz + 50MB + 30 + + + %date [%thread] %-5level [%logger{50}] %file:%line - %msg%n + + + + + + ${log.path}/error.log + + ${log.path}/%d{yyyy-MM}/error.%d{yyyy-MM-dd}.%i.log.gz + 50MB + 30 + + + %date [%thread] %-5level [%logger{50}] %file:%line - %msg%n + + + ERROR + + + + + + + + + + + + + + + + + diff --git a/pigx-flow/pigx-flow-engine/pom.xml b/pigx-flow/pigx-flow-engine/pom.xml new file mode 100644 index 000000000..9b9127c06 --- /dev/null +++ b/pigx-flow/pigx-flow-engine/pom.xml @@ -0,0 +1,22 @@ + + + + 4.0.0 + + + com.pig4cloud + pigx-flow + 5.2.0-snapshot + + + pigx-flow-engine + pom + flowable 工作流核心引擎 + + + + pigx-flow-engine-api + pigx-flow-engine-biz + + diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/pom.xml b/pigx-flow/pigx-flow-task/pigx-flow-task-api/pom.xml new file mode 100644 index 000000000..619bd9d9b --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + com.pig4cloud + pigx-flow-task + 5.2.0-snapshot + + + pigx-flow-task-api + + + + + com.pig4cloud + pigx-common-core + + + + com.baomidou + mybatis-plus-extension + + + + com.pig4cloud + pigx-common-feign + + + + com.pig4cloud + pigx-common-excel + + + diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/api/feign/RemoteFlowEngineService.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/api/feign/RemoteFlowEngineService.java new file mode 100644 index 000000000..3f2ccdeb6 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/api/feign/RemoteFlowEngineService.java @@ -0,0 +1,135 @@ +package com.pig4cloud.pigx.flow.task.api.feign; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.pig4cloud.pigx.common.core.constant.ServiceNameConstants; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.task.dto.*; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.Map; + +/** + * @author lengleng + * @date 2023/7/14 + */ +@FeignClient(contextId = "remoteFlowEngineService", value = ServiceNameConstants.FLOW_ENGINE_SERVER) +public interface RemoteFlowEngineService { + + /** + * 查询任务变量 + * @param variableQueryParamDto 变量查询参数 + * @return 任务变量结果 + */ + @PostMapping("/task/queryTaskVariables") + R> queryTaskVariables(@RequestBody VariableQueryParamDto variableQueryParamDto); + + /** + * 查询简单数据 + * @param userId 用户ID + * @return 索引页统计数据 + */ + @GetMapping("/process-instance/querySimpleData") + R querySimpleData(@RequestParam("userId") Long userId); + + /** + * 创建流程 + * @param map 流程JSON对象 + * @return 创建流程结果 + */ + @PostMapping("/flow/create") + R createFlow(@RequestBody Map map); + + /** + * 启动流程实例 + * @param processInstanceParamDto 流程实例参数 + * @return 启动流程结果 + */ + @PostMapping("/flow/start") + R startProcess(@RequestBody ProcessInstanceParamDto processInstanceParamDto); + + /** + * 查询待办任务 + * @param paramDto 任务查询参数 + * @return 待办任务列表 + */ + @PostMapping("/flow/queryAssignTask") + R> queryAssignTask(@RequestBody TaskQueryParamDto paramDto); + + /** + * 查询已完成任务 + * @param paramDto 任务查询参数 + * @return 已完成任务列表 + */ + @PostMapping("/flow/queryCompletedTask") + R> queryCompletedTask(@RequestBody TaskQueryParamDto paramDto); + + /** + * 完成任务 + * @param taskParamDto 任务参数 + * @return 完成任务结果 + */ + @PostMapping("/task/complete") + R completeTask(@RequestBody TaskParamDto taskParamDto); + + /** + * 设置任务负责人 + * @param taskParamDto 任务参数 + * @return 设置负责人结果 + */ + @PostMapping("/task/setAssignee") + R setAssignee(@RequestBody TaskParamDto taskParamDto); + + /** + * 停止流程实例 + * @param taskParamDto 任务参数 + * @return 停止流程实例结果 + */ + @PostMapping("/flow/stopProcessInstance") + R stopProcessInstance(@RequestBody TaskParamDto taskParamDto); + + /** + * 解决任务 + * @param taskParamDto 任务参数 + * @return 解决任务结果 + */ + @PostMapping("/task/resolveTask") + R resolveTask(@RequestBody TaskParamDto taskParamDto); + + /** + * 退回任务 + * @param taskParamDto 任务参数 + * @return 退回任务结果 + */ + @PostMapping("/task/back") + R back(@RequestBody TaskParamDto taskParamDto); + + /** + * 委派任务 + * @param taskParamDto 任务参数 + * @return 委派任务结果 + */ + @PostMapping("/task/delegateTask") + R delegateTask(@RequestBody TaskParamDto taskParamDto); + + /** + * 显示流程图 + * @param procInsId 流程实例ID + * @return 流程图地址 + */ + @GetMapping("/flow/showImg") + R showImg(@RequestParam("procInsId") String procInsId); + + /** + * 查询任务 + * @param taskId 任务ID + * @param userId 用户ID + * @return 任务查询结果 + */ + @GetMapping("/task/queryTask") + R queryTask(@RequestParam("taskId") String taskId, @RequestParam("userId") Long userId); + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/api/feign/RemoteFlowTaskService.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/api/feign/RemoteFlowTaskService.java new file mode 100644 index 000000000..caf7aadfc --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/api/feign/RemoteFlowTaskService.java @@ -0,0 +1,107 @@ +package com.pig4cloud.pigx.flow.task.api.feign; + +import com.pig4cloud.pigx.common.core.constant.ServiceNameConstants; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.task.dto.*; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.List; + +/** + * @author lengleng + * @date 2023/7/14 + */ +@FeignClient(contextId = "remoteFlowTaskService", value = ServiceNameConstants.FLOW_TASK_SERVER) +public interface RemoteFlowTaskService { + + /** + * 节点开始事件 + * @param nodeRecordParamDto + */ + @PostMapping("/remote/startNodeEvent") + void startNodeEvent(@RequestBody ProcessNodeRecordParamDto nodeRecordParamDto); + + /** + * 节点结束事件 + * @param nodeRecordParamDto + */ + @PostMapping("/remote/endNodeEvent") + void endNodeEvent(@RequestBody ProcessNodeRecordParamDto nodeRecordParamDto); + + /** + * 流程结束事件 + * @param processInstanceParamDto + */ + @PostMapping("/remote/endProcess") + void endProcessEvent(@RequestBody ProcessInstanceParamDto processInstanceParamDto); + + /** + * 创建流程事件 + * @param processInstanceRecordParamDto + */ + @PostMapping("/remote/createProcessEvent") + void createProcessEvent(@RequestBody ProcessInstanceRecordParamDto processInstanceRecordParamDto); + + /** + * 根据角色id集合查询用户id集合 + * @param roleIdList + */ + @PostMapping("/remote/queryUserIdListByRoleIdList") + R> queryUserIdListByRoleIdList(@RequestBody List roleIdList); + + /** + * 根据部门id集合查询所有的用户id集合 + * @param deptIdList + */ + @PostMapping("/remote/queryUserIdListByDepIdList") + R> queryUserIdListByDepIdList(@RequestBody List deptIdList); + + /** + * 查询流程管理员 + * @param flowId 流程id + */ + @GetMapping("/remote/queryProcessAdmin") + R queryProcessAdmin(@RequestParam("flowId") String flowId); + + /** + * 查询节点数据 + * @param flowId 流程id + * @param nodeId 节点id + * @return + */ + @GetMapping("/processNodeData/getNodeData") + R queryNodeOriData(@RequestParam("flowId") String flowId, @RequestParam("nodeId") String nodeId); + + /** + * 节点开始指派用户了 + * @param processNodeRecordAssignUserParamDto + */ + @PostMapping("/remote/startAssignUser") + R startAssignUser(@RequestBody ProcessNodeRecordAssignUserParamDto processNodeRecordAssignUserParamDto); + + /** + * 任务结束事件 + * @param processNodeRecordAssignUserParamDto + */ + @PostMapping("/remote/taskEndEvent") + R taskEndEvent(@RequestBody ProcessNodeRecordAssignUserParamDto processNodeRecordAssignUserParamDto); + + /** + * 保存抄送数据 + * @param processCopyDto + */ + @PostMapping("/remote/savecc") + R saveCC(@RequestBody ProcessCopyDto processCopyDto); + + /** + * 保存节点原始数据 + * @param processNodeDataDto + */ + @PostMapping("/processNodeData/saveNodeData") + R saveNodeOriData(@RequestBody ProcessNodeDataDto processNodeDataDto); + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/api/feign/packge-info.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/api/feign/packge-info.java new file mode 100644 index 000000000..5ffbac507 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/api/feign/packge-info.java @@ -0,0 +1,6 @@ +/* + @author pigx archetype + *

+ * feign client 存放目录,注意 @EnablePigxFeignClients 的扫描范围 + */ +package com.pig4cloud.pigx.flow.task.api.feign; \ No newline at end of file diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/CaptchaTypeEnum.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/CaptchaTypeEnum.java new file mode 100644 index 000000000..8418b55ae --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/CaptchaTypeEnum.java @@ -0,0 +1,28 @@ +package com.pig4cloud.pigx.flow.task.constant; + +/** + * EasyCaptcha 验证码类型枚举 + * + * @author haoxr + * @since 2023/03/24 + */ +public enum CaptchaTypeEnum { + + /** + * 算数 + */ + ARITHMETIC, + /** + * 中文 + */ + CHINESE, + /** + * 中文闪图 + */ + CHINESE_GIF, + /** + * 闪图 + */ + GIF, SPEC + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/FormTypeEnum.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/FormTypeEnum.java new file mode 100644 index 000000000..722c7f1fb --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/FormTypeEnum.java @@ -0,0 +1,30 @@ +package com.pig4cloud.pigx.flow.task.constant; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.ArrayList; + +/** + * 表单类型枚举 + */ +@Getter +@AllArgsConstructor +public enum FormTypeEnum { + + INPUT("Input", "单行文本", ""), TEXTAREA("Textarea", "多行文本", ""), NUMBER("Number", "数字", null), + DATE("Date", "日期", null), DATE_TIME("DateTime", "日期时间", null), + + SEQUENCE("Sequence", "发号器", null), LAYOUT("Layout", "明细", null), TIME("Time", "时间", null), + MONEY("Money", "金额", null), SINGLE_SELECT("SingleSelect", "单选", new ArrayList<>()), + SELECT_DEPT("SelectDept", "部门", new ArrayList<>()), SELECT_USER("SelectUser", "用户", new ArrayList<>()), + + ; + + private String type; + + private String name; + + private Object defaultValue; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/IBaseEnum.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/IBaseEnum.java new file mode 100644 index 000000000..ce365d614 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/IBaseEnum.java @@ -0,0 +1,76 @@ +package com.pig4cloud.pigx.flow.task.constant; + +import cn.hutool.core.util.ObjectUtil; + +import java.util.EnumSet; +import java.util.Objects; + +/** + * 枚举通用接口 + * + * @author haoxr + * @since 2022/3/27 12:06 + */ +public interface IBaseEnum { + + T getValue(); + + String getLabel(); + + /** + * 根据值获取枚举 + * @param value + * @param clazz + * @param 枚举 + * @return + */ + static & IBaseEnum> E getEnumByValue(Object value, Class clazz) { + Objects.requireNonNull(value); + EnumSet allEnums = EnumSet.allOf(clazz); // 获取类型下的所有枚举 + E matchEnum = allEnums.stream().filter(e -> ObjectUtil.equal(e.getValue(), value)).findFirst().orElse(null); + return matchEnum; + } + + /** + * 根据文本标签获取值 + * @param value + * @param clazz + * @param + * @return + */ + static & IBaseEnum> String getLabelByValue(Object value, Class clazz) { + Objects.requireNonNull(value); + EnumSet allEnums = EnumSet.allOf(clazz); // 获取类型下的所有枚举 + E matchEnum = allEnums.stream().filter(e -> ObjectUtil.equal(e.getValue(), value)).findFirst().orElse(null); + + String label = null; + if (matchEnum != null) { + label = matchEnum.getLabel(); + } + return label; + } + + /** + * 根据文本标签获取值 + * @param label + * @param clazz + * @param + * @return + */ + static & IBaseEnum> Object getValueByLabel(String label, Class clazz) { + Objects.requireNonNull(label); + EnumSet allEnums = EnumSet.allOf(clazz); // 获取类型下的所有枚举 + String finalLabel = label; + E matchEnum = allEnums.stream() + .filter(e -> ObjectUtil.equal(e.getLabel(), finalLabel)) + .findFirst() + .orElse(null); + + Object value = null; + if (matchEnum != null) { + value = matchEnum.getValue(); + } + return value; + } + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/MenuTypeEnum.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/MenuTypeEnum.java new file mode 100644 index 000000000..9baadad58 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/MenuTypeEnum.java @@ -0,0 +1,30 @@ +package com.pig4cloud.pigx.flow.task.constant; + +import com.baomidou.mybatisplus.annotation.EnumValue; +import lombok.Getter; + +/** + * 菜单类型枚举 + * + * @author haoxr + * @since 2022/4/23 9:36 + */ + +public enum MenuTypeEnum implements IBaseEnum { + + NULL(0, null), MENU(1, "菜单"), CATALOG(2, "目录"), EXTLINK(3, "外链"), BUTTON(4, "按钮"); + + @Getter + @EnumValue // Mybatis-Plus 提供注解表示插入数据库时插入该值 + private Integer value; + + @Getter + // @JsonValue // 表示对枚举序列化时返回此字段 + private String label; + + MenuTypeEnum(Integer value, String label) { + this.value = value; + this.label = label; + } + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/NodeStatusEnum.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/NodeStatusEnum.java new file mode 100644 index 000000000..3d5b581ec --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/NodeStatusEnum.java @@ -0,0 +1,16 @@ +package com.pig4cloud.pigx.flow.task.constant; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum NodeStatusEnum { + + WKS(0, "未开始"), JXZ(1, "进行中"), YJS(2, "已结束"),; + + private int code; + + private String name; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/NodeTypeEnum.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/NodeTypeEnum.java new file mode 100644 index 000000000..ac98964dd --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/NodeTypeEnum.java @@ -0,0 +1,27 @@ +package com.pig4cloud.pigx.flow.task.constant; + +import lombok.Getter; + +/** + * 节点枚举 + */ +@Getter +public enum NodeTypeEnum { + + ROOT("根节点", 0), + + APPROVAL("审批节点", 1), CC("抄送节点", 2), EXCLUSIVE_GATEWAY("条件分支", 4), PARALLEL_GATEWAY("并行分支", 5), EMPTY("空", 3) + + ; + + NodeTypeEnum(String name, Integer value) { + + this.name = name; + this.value = value; + } + + private String name; + + private Integer value; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/NodeUserTypeEnum.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/NodeUserTypeEnum.java new file mode 100644 index 000000000..860ddad41 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/NodeUserTypeEnum.java @@ -0,0 +1,19 @@ +package com.pig4cloud.pigx.flow.task.constant; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 用户节点类型枚举 + */ +@Getter +@AllArgsConstructor +public enum NodeUserTypeEnum { + + USER("user", "用户"), DEPT("dept", "部门"), ROLE("role", "角色"),; + + private String key; + + private String name; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/ProcessInstanceConstant.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/ProcessInstanceConstant.java new file mode 100644 index 000000000..ec79dff88 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/ProcessInstanceConstant.java @@ -0,0 +1,90 @@ +package com.pig4cloud.pigx.flow.task.constant; + +public class ProcessInstanceConstant { + + /** + * 空执行人 + */ + public static final Long DEFAULT_EMPTY_ASSIGN = -99999999L; + + /** + * 用户任务没有执行人的情况下如何处理 自动通过 + */ + public static final String USER_TASK_NOBODY_HANDLER_TO_PASS = "TO_PASS"; + + /** + * 转交给管理员 + */ + public static final String USER_TASK_NOBODY_HANDLER_TO_ADMIN = "TO_ADMIN"; + + /** + * 指定人员 + */ + public static final String USER_TASK_NOBODY_HANDLER_TO_USER = "TO_USER"; + + /** + * 结束流程 + */ + public static final String USER_TASK_NOBODY_HANDLER_TO_END = "TO_END"; + + /** + * 拒绝之后 结束流程 + */ + public static final String USER_TASK_REFUSE_TYPE_TO_END = "TO_END"; + + /** + * 拒绝之后 到某个节点 + */ + public static final String USER_TASK_REFUSE_TYPE_TO_NODE = "TO_NODE"; + + /** + * 会签 + */ + public static final int MULTIPLE_MODE_AL_SAME = 1; + + /** + * 或签 + */ + public static final int MULTIPLE_MODE_ONE = 2; + + /** + * 顺签 + */ + public static final int MULTIPLE_MODE_ALL_SORT = 3; + + public static class AssignedTypeClass { + + // 指定用户 + public static final int USER = 1; + + // 发起人自己 + public static final int SELF = 5; + + // 表单人员 + public static final int FORM_USER = 8; + + // 发起人自选 + public static final int SELF_SELECT = 4; + + // 角色 + public static final int ROLE = 3; + + } + + /** + * 表单权限 + */ + public static class FormPermClass { + + // 隐藏 + public static final String HIDE = "H"; + + // 只读 + public static final String READ = "R"; + + // 编辑 + public static final String EDIT = "E"; + + } + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/SecurityConstants.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/SecurityConstants.java new file mode 100644 index 000000000..b20ddb881 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/SecurityConstants.java @@ -0,0 +1,41 @@ +package com.pig4cloud.pigx.flow.task.constant; + +/** + * Security 常量 + * + * @author haoxr + * @since 2023/03/24 + */ +public interface SecurityConstants { + + /** + * 登录接口路径 + */ + String LOGIN_PATH = "/api/v1/auth/login"; + + /** + * Token 前缀 + */ + String TOKEN_PREFIX = "Bearer "; + + /** + * 请求头Token的Key + */ + String TOKEN_KEY = "Authorization"; + + /** + * 验证码缓存前缀 + */ + String VERIFY_CODE_CACHE_PREFIX = "AUTH:VERIFY_CODE:"; + + /** + * 用户权限集合缓存前缀 + */ + String USER_PERMS_CACHE_PREFIX = "AUTH:USER_PERMS:"; + + /** + * 黑名单Token缓存前缀 + */ + String BLACK_TOKEN_CACHE_PREFIX = "AUTH:BLACK_TOKEN:"; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/StatusEnum.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/StatusEnum.java new file mode 100644 index 000000000..3a5c2bd90 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/StatusEnum.java @@ -0,0 +1,26 @@ +package com.pig4cloud.pigx.flow.task.constant; + +import lombok.Getter; + +/** + * 状态枚举 + * + * @author haoxr + * @since 2022/10/14 + */ +public enum StatusEnum implements IBaseEnum { + + ENABLE(1, "启用"), DISABLE(0, "禁用"); + + @Getter + private Integer value; + + @Getter + private String label; + + StatusEnum(Integer value, String label) { + this.value = value; + this.label = label; + } + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/SystemConstants.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/SystemConstants.java new file mode 100644 index 000000000..8f0518f8a --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/SystemConstants.java @@ -0,0 +1,26 @@ +package com.pig4cloud.pigx.flow.task.constant; + +/** + * 系统常量 + * + * @author haoxr + * @since 2022/10/22 + */ +public interface SystemConstants { + + /** + * 根节点ID + */ + Long ROOT_NODE_ID = 0L; + + /** + * 系统默认密码 + */ + String DEFAULT_PASSWORD = "123456"; + + /** + * 超级管理员角色编码 + */ + String ROOT_ROLE_CODE = "ROOT"; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/packge-info.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/packge-info.java new file mode 100644 index 000000000..990c3b3fa --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/constant/packge-info.java @@ -0,0 +1,6 @@ +/* + * @author pigx archetype + *

+ * 常量和枚举定义 + */ +package com.pig4cloud.pigx.flow.task.constant; \ No newline at end of file diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/CheckChildDto.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/CheckChildDto.java new file mode 100644 index 000000000..43f95a194 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/CheckChildDto.java @@ -0,0 +1,23 @@ +package com.pig4cloud.pigx.flow.task.dto; + +import lombok.Data; + +import java.util.List; + +/** + * 检查子部门DTO + */ +@Data +public class CheckChildDto { + + /** + * 子部门ID + */ + private Long childId; + + /** + * 父部门ID列表 + */ + private List deptIdList; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/CheckParentDto.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/CheckParentDto.java new file mode 100644 index 000000000..75bbc4846 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/CheckParentDto.java @@ -0,0 +1,18 @@ +package com.pig4cloud.pigx.flow.task.dto; + +import lombok.Data; + +import java.util.List; + +/** + * 检查是否是给定的父级 + * + */ +@Data +public class CheckParentDto { + + private Long parentId; + + private List deptIdList; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/Condition.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/Condition.java new file mode 100644 index 000000000..a82d12566 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/Condition.java @@ -0,0 +1,31 @@ +package com.pig4cloud.pigx.flow.task.dto; + +import lombok.Data; + +/** + * 条件类 + */ +@Data +public class Condition { + + /** + * 条件键 + */ + private String key; + + /** + * 表达式 + */ + private String expression; + + /** + * 值 + */ + private Object value; + + /** + * 键类型 + */ + private String keyType; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/GroupCondition.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/GroupCondition.java new file mode 100644 index 000000000..2cfb9b461 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/GroupCondition.java @@ -0,0 +1,23 @@ +package com.pig4cloud.pigx.flow.task.dto; + +import lombok.Data; + +import java.util.List; + +/** + * 分组条件类 + */ +@Data +public class GroupCondition { + + /** + * 是否并行 + */ + private Boolean mode; + + /** + * 条件列表 + */ + private List conditionList; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/IndexPageStatistics.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/IndexPageStatistics.java new file mode 100644 index 000000000..1bc4bc192 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/IndexPageStatistics.java @@ -0,0 +1,33 @@ +package com.pig4cloud.pigx.flow.task.dto; + +import lombok.Builder; +import lombok.Data; + +/** + * 首页统计数据 + */ +@Data +@Builder +public class IndexPageStatistics { + + /** + * 待办数量 + */ + private Long pendingNum; + + /** + * 发起数量 + */ + private Long startedNum; + + /** + * 抄送任务 + */ + private Long copyNum; + + /** + * 完成数量 + */ + private Long completedNum; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/Nobody.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/Nobody.java new file mode 100644 index 000000000..b43f4cd40 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/Nobody.java @@ -0,0 +1,14 @@ +package com.pig4cloud.pigx.flow.task.dto; + +import lombok.Data; + +import java.util.List; + +@Data +public class Nobody { + + private String handler; + + private List assignedUser; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/Node.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/Node.java new file mode 100644 index 000000000..c0ebe2125 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/Node.java @@ -0,0 +1,56 @@ +package com.pig4cloud.pigx.flow.task.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.List; +import java.util.Map; + +@Data +public class Node { + + private String id; + + private String parentId; + + private String headId; + + private String tailId; + + private String placeHolder; + + private Integer type; + + @JsonProperty(value = "nodeName") + private String name; + + private Boolean error; + + @JsonProperty("childNode") + private Node children; + + private Integer assignedType; + + private Boolean multiple; + + private Integer multipleMode; + + private Integer deptLeaderLevel; + + private String formUserId; + + private String formUserName; + + private List nodeUserList; + + private List conditionNodes; + + private Map formPerms; + + private Nobody nobody; + + private Boolean groupMode; + + private List conditionList; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/NodeHttpResultVO.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/NodeHttpResultVO.java new file mode 100644 index 000000000..2686c4ffc --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/NodeHttpResultVO.java @@ -0,0 +1,17 @@ +package com.pig4cloud.pigx.flow.task.dto; + +import lombok.Data; + +import java.util.Map; + +/** + * 节点处理http请求结果对象 + */ +@Data +public class NodeHttpResultVO { + + private Boolean ok; + + private Map data; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/NodeUser.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/NodeUser.java new file mode 100644 index 000000000..a8fa54ca4 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/NodeUser.java @@ -0,0 +1,39 @@ +package com.pig4cloud.pigx.flow.task.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 节点用户对象 + */ +@NoArgsConstructor +@Data +@Builder +@AllArgsConstructor +public class NodeUser { + + /** + * 用户od + */ + private Long id; + + /** + * 用户名称 + */ + private String name; + + /** + * 类型 + */ + private String type; + + /** + * 选择 + */ + private Boolean selected; + + private String avatar; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/ProcessCopyDto.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/ProcessCopyDto.java new file mode 100644 index 000000000..ef06c162e --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/ProcessCopyDto.java @@ -0,0 +1,52 @@ +package com.pig4cloud.pigx.flow.task.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.util.Date; + +@Data +public class ProcessCopyDto { + + /** + * 当前节点时间 + */ + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + private Date nodeTime; + + /** + * 发起人 + */ + private Long startUserId; + + /** + * 流程id + */ + private String flowId; + + /** + * 实例id + */ + private String processInstanceId; + + /** + * 节点id + */ + private String nodeId; + + /** + * 节点 名称 + */ + private String nodeName; + + /** + * 表单数据 + */ + private String formData; + + /** + * 抄送人id + */ + private Long userId; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/ProcessInstanceParamDto.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/ProcessInstanceParamDto.java new file mode 100644 index 000000000..d395fb999 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/ProcessInstanceParamDto.java @@ -0,0 +1,34 @@ +package com.pig4cloud.pigx.flow.task.dto; + +import lombok.Data; + +import java.util.HashMap; +import java.util.Map; + +/** + * 流程实例参数对象 + */ +@Data +public class ProcessInstanceParamDto { + + /** + * 流程id + */ + private String flowId; + + /** + * 参数集合 + */ + private Map paramMap = new HashMap<>(); + + /** + * 发起人 + */ + private String startUserId; + + /** + * 实例id + */ + private String processInstanceId; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/ProcessInstanceRecordParamDto.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/ProcessInstanceRecordParamDto.java new file mode 100644 index 000000000..41713a43d --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/ProcessInstanceRecordParamDto.java @@ -0,0 +1,40 @@ +package com.pig4cloud.pigx.flow.task.dto; + +import lombok.Getter; +import lombok.Setter; + +/** + *

+ * 流程记录 + *

+ * + * @author Vincent + * @since 2023-05-07 + */ +@Getter +@Setter +public class ProcessInstanceRecordParamDto { + + /** + * 用户id + */ + private Long userId; + + /** + * 流程id + */ + private String flowId; + + /** + * 流程实例id + */ + private String processInstanceId; + + private String parentProcessInstanceId; + + /** + * 表单数据 + */ + private String formData; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/ProcessNodeDataDto.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/ProcessNodeDataDto.java new file mode 100644 index 000000000..ff3ada016 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/ProcessNodeDataDto.java @@ -0,0 +1,14 @@ +package com.pig4cloud.pigx.flow.task.dto; + +import lombok.Data; + +@Data +public class ProcessNodeDataDto { + + private String flowId; + + private String nodeId; + + private String data; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/ProcessNodeRecordAssignUserParamDto.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/ProcessNodeRecordAssignUserParamDto.java new file mode 100644 index 000000000..b640f866d --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/ProcessNodeRecordAssignUserParamDto.java @@ -0,0 +1,66 @@ +package com.pig4cloud.pigx.flow.task.dto; + +import lombok.Data; + +/** + * 流程节点记录-执行人 + */ +@Data +public class ProcessNodeRecordAssignUserParamDto { + + /** + * 流程id (process id) + */ + private String flowId; + + /** + * 流程实例id (process instance id) + */ + private String processInstanceId; + + /** + * 表单数据 (form data) + */ + private String data; + + /** + * 本地数据 (local data) + */ + private String localData; + + /** + * 节点id (node id) + */ + private String nodeId; + + /** + * 用户id (user id) + */ + private Long userId; + + /** + * 执行id (execution id) + */ + private String executionId; + + /** + * 任务id (task id) + */ + private String taskId; + + /** + * 审批描述 (approval description) + */ + private String approveDesc; + + /** + * 节点名称 (node name) + */ + private String nodeName; + + /** + * 任务类型 (task type) + */ + private String taskType; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/ProcessNodeRecordParamDto.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/ProcessNodeRecordParamDto.java new file mode 100644 index 000000000..c8c19613d --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/ProcessNodeRecordParamDto.java @@ -0,0 +1,61 @@ +package com.pig4cloud.pigx.flow.task.dto; + +import lombok.Data; + +/** + * 流程节点记录 + */ +@Data +public class ProcessNodeRecordParamDto { + + /** + * 流程id (process id) + */ + private String flowId; + + /** + * 流程实例id (process instance id) + */ + private String processInstanceId; + + /** + * 表单数据 (form data) + */ + private String data; + + /** + * 节点id (node id) + */ + private String nodeId; + + /** + * 节点类型 (node type) + */ + private String nodeType; + + /** + * 节点名字 (node name) + */ + private String nodeName; + + /** + * 执行id (execution id) + */ + private String executionId; + + /** + * 任务id (task id) + */ + private String taskId; + + /** + * 审批描述 (approval description) + */ + private String approveDesc; + + /** + * 任务类型 (task type) + */ + private String taskType; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/TaskDto.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/TaskDto.java new file mode 100644 index 000000000..032417ba3 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/TaskDto.java @@ -0,0 +1,97 @@ +package com.pig4cloud.pigx.flow.task.dto; + +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.Date; +import java.util.Map; + +/** + * 任务对象 + */ +@Data +public class TaskDto { + + /** + * 流程id + */ + private String flowId; + + /** + * 参数集合 + */ + private Map paramMap; + + /** + * 实例id + */ + private String processInstanceId; + + /** + * 执行id + */ + private String executionId; + + /** + * 耗时 + */ + private Long durationInMillis; + + /** + * 任务id + */ + private String taskId; + + /** + * 执行人 + */ + private String assign; + + /** + * 任务名称 + */ + private String taskName; + + /** + * 节点id + */ + private String nodeId; + + /** + * 任务创建时间 + */ + private Date taskCreateTime; + + private Date taskEndTime; + + /** + * 流程组名字 + */ + private String groupName; + + /** + * 发起人id + */ + private Long rootUserId; + + /** + * 发起人名字 + */ + private String rootUserName; + + /** + * 发起人头像 + */ + private String rootUserAvatarUrl; + + /** + * 发起时间 + */ + private LocalDateTime startTime; + + /** + * 流程名称 + */ + private String processName; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/TaskParamDto.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/TaskParamDto.java new file mode 100644 index 000000000..36689eeae --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/TaskParamDto.java @@ -0,0 +1,59 @@ +package com.pig4cloud.pigx.flow.task.dto; + +import lombok.Data; + +import java.util.List; +import java.util.Map; + +/** + * 任务完成参数对象 + * + */ +@Data +public class TaskParamDto { + + private String processInstanceId; + + private List processInstanceIdList; + + /** + * 节点id + */ + private String nodeId; + + /** + * 添加子流程发起人 + */ + private Boolean appendChildProcessRootId; + + /** + * 任务id + */ + private String taskId; + + /** + * 用户id + */ + private String userId; + + /** + * 模板用户id + */ + private String targetUserId; + + /** + * 参数 + */ + private Map paramMap; + + /** + * 任务本地变量 + */ + private Map taskLocalParamMap; + + /** + * 模板节点 + */ + private String targetNodeId; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/TaskQueryParamDto.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/TaskQueryParamDto.java new file mode 100644 index 000000000..f05afebfe --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/TaskQueryParamDto.java @@ -0,0 +1,43 @@ +package com.pig4cloud.pigx.flow.task.dto; + +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 用户任务查询参数 + */ +@Data +public class TaskQueryParamDto { + + /** + * 任务执行人 + */ + private String assign; + + /** + * 页码 + */ + private Integer pageNum; + + /** + * 每页的数量 + */ + private Integer pageSize; + + /** + * 流程名称 + */ + private String processName; + + /** + * 任务时间 + */ + private LocalDateTime[] taskTime; + + /** + * 状态 + */ + private Integer status; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/TaskResultDto.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/TaskResultDto.java new file mode 100644 index 000000000..d7c501f1c --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/TaskResultDto.java @@ -0,0 +1,45 @@ +package com.pig4cloud.pigx.flow.task.dto; + +import lombok.Data; + +import java.util.Map; + +/** + * 任务结果对象 + * + */ +@Data +public class TaskResultDto { + + private Boolean currentTask; + + /** + * 流程id + */ + private String flowId; + + private Node taskNode; + + private String nodeId; + + /** + * 实例id + */ + private String processInstanceId; + + /** + * 委派状态 + */ + private String delegationState; + + /** + * 是否允许继续委派 + */ + private Boolean delegate; + + /** + * 所有变量 + */ + private Map variableAll; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/VariableQueryParamDto.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/VariableQueryParamDto.java new file mode 100644 index 000000000..6f07f677d --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/VariableQueryParamDto.java @@ -0,0 +1,16 @@ +package com.pig4cloud.pigx.flow.task.dto; + +import lombok.Data; + +import java.util.List; + +@Data +public class VariableQueryParamDto { + + private String taskId; + + private List keyList; + + private String executionId; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/packge-info.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/packge-info.java new file mode 100644 index 000000000..d83dba1e1 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/dto/packge-info.java @@ -0,0 +1,6 @@ +/* + * @author pigx archetype + *

+ * DTO 存放目录 + */ +package com.pig4cloud.pigx.flow.task.dto; \ No newline at end of file diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/entity/Process.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/entity/Process.java new file mode 100644 index 000000000..17ba5268b --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/entity/Process.java @@ -0,0 +1,136 @@ +package com.pig4cloud.pigx.flow.task.entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; + +/** + *

+ * + *

+ * + * @author Vincent + * @since 2023-07-06 + */ +@Getter +@Setter +@Accessors(chain = true) +@TableName("`process`") +public class Process { + + /** + * 表单ID + */ + @TableField("`flow_id`") + private String flowId; + + /** + * 表单名称 + */ + @TableField("`name`") + private String name; + + /** + * 图标配置 + */ + @TableField("`logo`") + private String logo; + + /** + * 设置项 + */ + @TableField("`settings`") + private String settings; + + /** + * 分组ID + */ + @TableField("`group_id`") + private Long groupId; + + /** + * 表单设置内容 + */ + @TableField("`form_items`") + private String formItems; + + /** + * 流程设置内容 + */ + @TableField("`process`") + private String process; + + /** + * 备注 + */ + @TableField("`remark`") + private String remark; + + @TableField("`sort`") + private Integer sort; + + /** + * 0 正常 1=隐藏 + */ + @TableField("`is_hidden`") + private Boolean hidden; + + /** + * 0 正常 1=停用 + */ + @TableField("`is_stop`") + private Boolean stop; + + /** + * 流程管理员 + */ + @TableField("`admin_id`") + private Long adminId; + + /** + * 唯一性id + */ + @TableField("`unique_id`") + private String uniqueId; + + /** + * 管理员 + */ + @TableField("`admin`") + private String admin; + + /** + * 范围描述显示 + */ + @TableField("`range_show`") + private String rangeShow; + + /** + * 用户id + */ + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + /** + * 逻辑删除字段 + */ + @TableLogic + @TableField(fill = FieldFill.INSERT) + private String delFlag; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private LocalDateTime updateTime; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/entity/ProcessCopy.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/entity/ProcessCopy.java new file mode 100644 index 000000000..f018f45cf --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/entity/ProcessCopy.java @@ -0,0 +1,121 @@ +package com.pig4cloud.pigx.flow.task.entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; + +/** + *

+ * 流程抄送数据 + *

+ * + * @author Vincent + * @since 2023-07-06 + */ +@Getter +@Setter +@Accessors(chain = true) +@TableName("`process_copy`") +public class ProcessCopy { + + /** + * 流程发起时间 + */ + @TableField("`start_time`") + private LocalDateTime startTime; + + /** + * 当前节点时间 + */ + @TableField("`node_time`") + private LocalDateTime nodeTime; + + /** + * 发起人 + */ + @TableField("`start_user_id`") + private Long startUserId; + + /** + * 流程id + */ + @TableField("`flow_id`") + private String flowId; + + /** + * 实例id + */ + @TableField("`process_instance_id`") + private String processInstanceId; + + /** + * 节点id + */ + @TableField("`node_id`") + private String nodeId; + + /** + * 分组id + */ + @TableField("`group_id`") + private Long groupId; + + /** + * 分组名称 + */ + @TableField("`group_name`") + private String groupName; + + /** + * 流程名称 + */ + @TableField("`process_name`") + private String processName; + + /** + * 节点 名称 + */ + @TableField("`node_name`") + private String nodeName; + + /** + * 表单数据 + */ + @TableField("`form_data`") + private String formData; + + /** + * 抄送人id + */ + @TableField("`user_id`") + private Long userId; + + /** + * 用户id + */ + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + /** + * 逻辑删除字段 + */ + @TableLogic + @TableField(fill = FieldFill.INSERT) + private String delFlag; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private LocalDateTime updateTime; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/entity/ProcessGroup.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/entity/ProcessGroup.java new file mode 100644 index 000000000..9721034e7 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/entity/ProcessGroup.java @@ -0,0 +1,61 @@ +package com.pig4cloud.pigx.flow.task.entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; + +/** + *

+ * + *

+ * + * @author Vincent + * @since 2023-07-06 + */ +@Getter +@Setter +@Accessors(chain = true) +@TableName("`process_group`") +public class ProcessGroup { + + /** + * 分组名 + */ + @TableField("`group_name`") + private String groupName; + + /** + * 排序 + */ + @TableField("`sort`") + private Integer sort; + + /** + * 用户id + */ + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + /** + * 逻辑删除字段 + */ + @TableLogic + @TableField(fill = FieldFill.INSERT) + private String delFlag; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private LocalDateTime updateTime; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/entity/ProcessInstanceRecord.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/entity/ProcessInstanceRecord.java new file mode 100644 index 000000000..7f20c575d --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/entity/ProcessInstanceRecord.java @@ -0,0 +1,116 @@ +package com.pig4cloud.pigx.flow.task.entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; +import java.util.Date; + +/** + *

+ * 流程记录 + *

+ * + * @author Vincent + * @since 2023-07-06 + */ +@Getter +@Setter +@Accessors(chain = true) +@TableName("`process_instance_record`") +public class ProcessInstanceRecord { + + /** + * 流程名字 + */ + @TableField("`name`") + private String name; + + /** + * 头像 + */ + @TableField("`logo`") + private String logo; + + /** + * 用户id + */ + @TableField("`user_id`") + private Long userId; + + /** + * 流程id + */ + @TableField("`flow_id`") + private String flowId; + + /** + * 流程实例id + */ + @TableField("`process_instance_id`") + private String processInstanceId; + + /** + * 表单数据 + */ + @TableField("`form_data`") + private String formData; + + /** + * 组id + */ + @TableField("`group_id`") + private Long groupId; + + /** + * 组名称 + */ + @TableField("`group_name`") + private String groupName; + + /** + * 状态 + */ + @TableField("`status`") + private Integer status; + + /** + * 结束时间 + */ + @TableField("`end_time`") + private Date endTime; + + /** + * 上级流程实例id + */ + @TableField("`parent_process_instance_id`") + private String parentProcessInstanceId; + + /** + * 用户id + */ + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + /** + * 逻辑删除字段 + */ + @TableLogic + @TableField(fill = FieldFill.INSERT) + private String delFlag; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private LocalDateTime updateTime; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/entity/ProcessNodeData.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/entity/ProcessNodeData.java new file mode 100644 index 000000000..1b2dedf57 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/entity/ProcessNodeData.java @@ -0,0 +1,64 @@ +package com.pig4cloud.pigx.flow.task.entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; + +/** + *

+ * 流程节点数据 + *

+ * + * @author Vincent + * @since 2023-07-06 + */ +@Getter +@Setter +@Accessors(chain = true) +@TableName("`process_node_data`") +public class ProcessNodeData { + + /** + * 流程id + */ + @TableField("`flow_id`") + private String flowId; + + /** + * 表单数据 + */ + @TableField("`data`") + private String data; + + @TableField("`node_id`") + private String nodeId; + + /** + * 用户id + */ + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + /** + * 逻辑删除字段 + */ + @TableLogic + @TableField(fill = FieldFill.INSERT) + private String delFlag; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private LocalDateTime updateTime; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/entity/ProcessNodeRecord.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/entity/ProcessNodeRecord.java new file mode 100644 index 000000000..efbfe8f0a --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/entity/ProcessNodeRecord.java @@ -0,0 +1,107 @@ +package com.pig4cloud.pigx.flow.task.entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; +import java.util.Date; + +/** + *

+ * 流程节点记录 + *

+ * + * @author Vincent + * @since 2023-07-06 + */ +@Getter +@Setter +@Accessors(chain = true) +@TableName("`process_node_record`") +public class ProcessNodeRecord { + + /** + * 流程id + */ + @TableField("`flow_id`") + private String flowId; + + /** + * 流程实例id + */ + @TableField("`process_instance_id`") + private String processInstanceId; + + /** + * 表单数据 + */ + @TableField("`data`") + private String data; + + @TableField("`node_id`") + private String nodeId; + + /** + * 节点类型 + */ + @TableField("`node_type`") + private String nodeType; + + /** + * 节点名字 + */ + @TableField("`node_name`") + private String nodeName; + + /** + * 节点状态 + */ + @TableField("`status`") + private Integer status; + + /** + * 开始时间 + */ + @TableField("`start_time`") + private Date startTime; + + /** + * 结束时间 + */ + @TableField("`end_time`") + private Date endTime; + + /** + * 执行id + */ + @TableField("`execution_id`") + private String executionId; + + /** + * 用户id + */ + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + /** + * 逻辑删除字段 + */ + @TableLogic + @TableField(fill = FieldFill.INSERT) + private String delFlag; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private LocalDateTime updateTime; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/entity/ProcessNodeRecordAssignUser.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/entity/ProcessNodeRecordAssignUser.java new file mode 100644 index 000000000..3dfa22193 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/entity/ProcessNodeRecordAssignUser.java @@ -0,0 +1,130 @@ +package com.pig4cloud.pigx.flow.task.entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; + +/** + *

+ * 流程节点记录-执行人 + *

+ * + * @author Vincent + * @since 2023-07-06 + */ +@Getter +@Setter +@Accessors(chain = true) +@TableName("`process_node_record_assign_user`") +public class ProcessNodeRecordAssignUser { + + /** + * 流程id + */ + @TableField("`flow_id`") + private String flowId; + + /** + * 流程实例id + */ + @TableField("`process_instance_id`") + private String processInstanceId; + + /** + * 表单数据 + */ + @TableField("`data`") + private String data; + + @TableField("`node_id`") + private String nodeId; + + /** + * 用户id + */ + @TableField("`user_id`") + private String userId; + + /** + * 节点状态 + */ + @TableField("`status`") + private Integer status; + + /** + * 开始时间 + */ + @TableField("`start_time`") + private LocalDateTime startTime; + + /** + * 结束时间 + */ + @TableField("`end_time`") + private LocalDateTime endTime; + + /** + * 执行id + */ + @TableField("`execution_id`") + private String executionId; + + /** + * 任务id + */ + @TableField("`task_id`") + private String taskId; + + /** + * 审批意见 + */ + @TableField("`approve_desc`") + private String approveDesc; + + /** + * 节点名称 + */ + @TableField("`node_name`") + private String nodeName; + + /** + * 任务类型 + */ + @TableField("`task_type`") + private String taskType; + + /** + * 表单本地数据 + */ + @TableField("`local_data`") + private String localData; + + /** + * 用户id + */ + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + /** + * 逻辑删除字段 + */ + @TableLogic + @TableField(fill = FieldFill.INSERT) + private String delFlag; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private LocalDateTime updateTime; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/entity/ProcessStarter.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/entity/ProcessStarter.java new file mode 100644 index 000000000..ba36003ce --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/entity/ProcessStarter.java @@ -0,0 +1,67 @@ +package com.pig4cloud.pigx.flow.task.entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; + +/** + *

+ * 流程发起人 + *

+ * + * @author Vincent + * @since 2023-07-06 + */ +@Getter +@Setter +@Accessors(chain = true) +@TableName("`process_starter`") +public class ProcessStarter { + + /** + * 用户id或者部门id + */ + @TableField("`type_id`") + private Long typeId; + + /** + * 类型 user dept + */ + @TableField("`type`") + private String type; + + /** + * 流程id + */ + @TableField("`process_id`") + private Long processId; + + /** + * 用户id + */ + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + /** + * 逻辑删除字段 + */ + @TableLogic + @TableField(fill = FieldFill.INSERT) + private String delFlag; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private LocalDateTime updateTime; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/entity/packge-info.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/entity/packge-info.java new file mode 100644 index 000000000..baecb2823 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/entity/packge-info.java @@ -0,0 +1,6 @@ +/* + * @author pigx archetype + *

+ * 实体 存放目录 + */ +package com.pig4cloud.pigx.flow.task.entity; \ No newline at end of file diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/utils/NodeUtil.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/utils/NodeUtil.java new file mode 100644 index 000000000..0aa21dc78 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/utils/NodeUtil.java @@ -0,0 +1,61 @@ +package com.pig4cloud.pigx.flow.task.utils; + +import cn.hutool.core.util.StrUtil; +import com.pig4cloud.pigx.flow.task.constant.NodeTypeEnum; +import com.pig4cloud.pigx.flow.task.constant.ProcessInstanceConstant; +import com.pig4cloud.pigx.flow.task.dto.Node; + +import java.util.ArrayList; +import java.util.List; + +public class NodeUtil { + + public static String getFlowId(String processDefinitionId) { + return StrUtil.subBefore(processDefinitionId, ":", false); + } + + public static boolean isNode(Node childNode) { + return childNode != null && StrUtil.isNotBlank(childNode.getId()); + } + + /** + * 需要发起人选择用户的节点 + * @param node + */ + public static List selectUserNodeId(Node node) { + List list = new ArrayList<>(); + + if (!isNode(node)) { + return list; + } + + Integer type = node.getType(); + + if (type == NodeTypeEnum.APPROVAL.getValue().intValue()) { + + Integer assignedType = node.getAssignedType(); + + boolean selfSelect = assignedType == ProcessInstanceConstant.AssignedTypeClass.SELF_SELECT; + if (selfSelect) { + list.add(node.getId()); + } + } + + if (type == NodeTypeEnum.EXCLUSIVE_GATEWAY.getValue().intValue() + || type == NodeTypeEnum.PARALLEL_GATEWAY.getValue().intValue()) { + + // 条件分支 + List branchs = node.getConditionNodes(); + for (Node branch : branchs) { + Node children = branch.getChildren(); + List strings = selectUserNodeId(children); + list.addAll(strings); + } + } + + List next = selectUserNodeId(node.getChildren()); + list.addAll(next); + return list; + } + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/vo/ErrorRspVo.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/vo/ErrorRspVo.java new file mode 100644 index 000000000..25339cf47 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/vo/ErrorRspVo.java @@ -0,0 +1,20 @@ +package com.pig4cloud.pigx.flow.task.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; + +/** + * @author : willian fu + * @date : 2022/7/4 + */ +@Data +@AllArgsConstructor +public class ErrorRspVo { + + private Integer code; + + private String msg; + + private String desp; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/vo/FormGroupVo.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/vo/FormGroupVo.java new file mode 100644 index 000000000..dc3779fd4 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/vo/FormGroupVo.java @@ -0,0 +1,57 @@ +package com.pig4cloud.pigx.flow.task.vo; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * @author : willian fu + * @date : 2020/9/21 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FormGroupVo { + + private Long id; + + /** + * 流程名字 + */ + private String name; + + /** + * 流程 + */ + private List items; + + @Data + @Builder + @AllArgsConstructor + public static class FlowVo { + + private String flowId; + + /** + * 发起范围 + */ + private String rangeShow; + + private String name; + + private String logo; + + private Boolean stop; + + private String remark; + + private LocalDateTime updated; + + } + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/vo/FormItemVO.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/vo/FormItemVO.java new file mode 100644 index 000000000..97642daed --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/vo/FormItemVO.java @@ -0,0 +1,58 @@ +package com.pig4cloud.pigx.flow.task.vo; + +import lombok.Builder; +import lombok.Data; + +/** + * 表单 + */ +@Data +@Builder +public class FormItemVO { + + private String id; + + private String perm; + + private String icon; + + private String name; + + private String type; + + private Boolean required; + + private String typeName; + + private String placeholder; + + private Props props; + + @Data + public static class Props { + + private Object value; + + private Object dictValue; + + private Object options; + + private Boolean self; + + private Boolean multi; + + private Object oriForm; + + private Object maxLength; + + private Object minLength; + + private Object regex; + + private Object regexDesc; + + private String prefix; + + } + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/vo/FormRemoteSelectOptionParamVo.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/vo/FormRemoteSelectOptionParamVo.java new file mode 100644 index 000000000..05af3d375 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/vo/FormRemoteSelectOptionParamVo.java @@ -0,0 +1,16 @@ +package com.pig4cloud.pigx.flow.task.vo; + +import lombok.Data; + +/** + * 表单远程的下拉选项 + */ +@Data +public class FormRemoteSelectOptionParamVo { + + /** + * 远程请求地址 + */ + private String remoteUrl; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/vo/NodeFormatParamVo.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/vo/NodeFormatParamVo.java new file mode 100644 index 000000000..14be488be --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/vo/NodeFormatParamVo.java @@ -0,0 +1,18 @@ +package com.pig4cloud.pigx.flow.task.vo; + +import lombok.Data; + +import java.util.Map; + +@Data +public class NodeFormatParamVo { + + private String flowId; + + private String processInstanceId; + + private String taskId; + + private Map paramMap; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/vo/NodeVo.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/vo/NodeVo.java new file mode 100644 index 000000000..37060f6e1 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/vo/NodeVo.java @@ -0,0 +1,63 @@ +package com.pig4cloud.pigx.flow.task.vo; + +import lombok.Data; + +import java.util.List; + +/** + * 流程节点显示对象 + */ +@Data +public class NodeVo { + + /** + * nodeId + */ + private String id; + + /** + * 用户列表 + */ + private List userVoList; + + /** + * 显示 + */ + private String placeholder; + + /** + * 状态 1进行中2已完成 + */ + private Integer status; + + /** + * 节点名称 + */ + private String name; + + /** + * 节点类型 + */ + private Object type; + + /** + * 发起人选择用户 + */ + private Boolean selectUser; + + /** + * 是否多选 + */ + private Boolean multiple; + + /** + * 子级列表 + */ + private List children; + + /** + * 分支列表 + */ + private List branch; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/vo/OrgTreeVo.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/vo/OrgTreeVo.java new file mode 100644 index 000000000..f105bdb95 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/vo/OrgTreeVo.java @@ -0,0 +1,42 @@ +package com.pig4cloud.pigx.flow.task.vo; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author : willian fu + * @version : 1.0 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class OrgTreeVo { + + /** + * 用户od + */ + private Long id; + + /** + * 用户名称 + */ + private String name; + + /** + * 类型 + */ + private String type; + + /** + * 选择 + */ + private Boolean selected; + + private String avatar; + + private Integer status = 1; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/vo/ProcessCopyVo.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/vo/ProcessCopyVo.java new file mode 100644 index 000000000..b66206317 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/vo/ProcessCopyVo.java @@ -0,0 +1,11 @@ +package com.pig4cloud.pigx.flow.task.vo; + +import com.pig4cloud.pigx.flow.task.entity.ProcessCopy; +import lombok.Data; + +@Data +public class ProcessCopyVo extends ProcessCopy { + + private String startUserName; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/vo/ProcessVO.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/vo/ProcessVO.java new file mode 100644 index 000000000..26898351a --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/vo/ProcessVO.java @@ -0,0 +1,19 @@ +package com.pig4cloud.pigx.flow.task.vo; + +import com.pig4cloud.pigx.flow.task.entity.Process; +import lombok.Data; + +import java.util.List; +import java.util.Map; + +@Data +public class ProcessVO extends Process { + + /** + * 需要发起人选择的节点id + */ + private List selectUserNodeId; + + private Map variableMap; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/vo/UserVo.java b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/vo/UserVo.java new file mode 100644 index 000000000..1d835f483 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-api/src/main/java/com/pig4cloud/pigx/flow/task/vo/UserVo.java @@ -0,0 +1,42 @@ +package com.pig4cloud.pigx.flow.task.vo; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class UserVo { + + /** + * 用户od + */ + private Long id; + + /** + * 用户名称 + */ + private String name; + + private LocalDateTime showTime; + + private String avatar; + + /** + * 意见 + */ + private String approveDesc; + + private String operType; + + /** + * 状态 1进行中2已完成 + */ + private Integer status = 0; + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/pom.xml b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/pom.xml new file mode 100644 index 000000000..075f35044 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/pom.xml @@ -0,0 +1,119 @@ + + + 4.0.0 + + com.pig4cloud + pigx-flow-task + 5.2.0-snapshot + + + pigx-flow-task-biz + + + + + org.springframework.boot + spring-boot-starter-undertow + + + + org.springframework.boot + spring-boot-starter-web + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-config + + + + com.pig4cloud + pigx-common-data + + + + com.pig4cloud + pigx-common-sequence + + + + com.pig4cloud + pigx-common-security + + + + com.pig4cloud + pigx-common-xss + + + + com.pig4cloud + pigx-common-sentinel + + + + com.pig4cloud + pigx-common-feign + + + + com.pig4cloud + pigx-flow-task-api + + + + com.pig4cloud + pigx-common-log + + + + com.baomidou + mybatis-plus-boot-starter + + + com.alibaba.fastjson2 + fastjson2 + 2.0.28 + + + + com.alibaba + druid-spring-boot-3-starter + + + + com.mysql + mysql-connector-j + + + + com.pig4cloud + pigx-common-swagger + + + + org.springframework.boot + spring-boot-starter-test + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + io.fabric8 + docker-maven-plugin + + + + diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/PigxFlowTaskApplication.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/PigxFlowTaskApplication.java new file mode 100644 index 000000000..ce820a08e --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/PigxFlowTaskApplication.java @@ -0,0 +1,26 @@ +package com.pig4cloud.pigx.flow.task; + +import com.pig4cloud.pigx.common.feign.annotation.EnablePigxFeignClients; +import com.pig4cloud.pigx.common.security.annotation.EnablePigxResourceServer; +import com.pig4cloud.pigx.common.swagger.annotation.EnableOpenApi; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; + +/** + * @author pigx archetype + *

+ * 项目启动类 + */ +@EnableOpenApi("task") +@EnablePigxFeignClients +@EnableDiscoveryClient +@EnablePigxResourceServer +@SpringBootApplication +public class PigxFlowTaskApplication { + + public static void main(String[] args) { + SpringApplication.run(PigxFlowTaskApplication.class, args); + } + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/config/SequenceConfig.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/config/SequenceConfig.java new file mode 100644 index 000000000..2e3383177 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/config/SequenceConfig.java @@ -0,0 +1,39 @@ +package com.pig4cloud.pigx.flow.task.config; + +import cn.hutool.core.date.DateUtil; +import com.pig4cloud.pigx.common.data.tenant.TenantContextHolder; +import com.pig4cloud.pigx.common.sequence.builder.DbSeqBuilder; +import com.pig4cloud.pigx.common.sequence.properties.SequenceDbProperties; +import com.pig4cloud.pigx.common.sequence.sequence.Sequence; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.sql.DataSource; + +/** + * @author lengleng + * @date 2023-07-19 + *

+ * 设置发号器生成规则 + */ +@Configuration +public class SequenceConfig { + + /** + * 工作流发号器 + * @param dataSource + * @param properties + * @return + */ + @Bean + public Sequence flowSequence(DataSource dataSource, SequenceDbProperties properties) { + return DbSeqBuilder.create() + .bizName(() -> String.format("flow_%s_%s", TenantContextHolder.getTenantId(), DateUtil.today())) + .dataSource(dataSource) + .step(properties.getStep()) + .retryTimes(properties.getRetryTimes()) + .tableName(properties.getTableName()) + .build(); + } + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/controller/CombinationGroupController.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/controller/CombinationGroupController.java new file mode 100644 index 000000000..2c5ba3e1c --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/controller/CombinationGroupController.java @@ -0,0 +1,39 @@ +package com.pig4cloud.pigx.flow.task.controller; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.task.service.ICombinationGroupService; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 组聚合接口控制器 + */ +@RestController +@RequiredArgsConstructor +@RequestMapping("/combination/group") +public class CombinationGroupController { + + private final ICombinationGroupService combinationGroupService; + + /** + * 查询表单组包含流程 + * @return 表单组数据 + */ + @GetMapping("listGroupWithProcess") + public R listGroupWithProcess(Page page, Long groupId) { + return combinationGroupService.listGroupWithProcess(page, groupId); + } + + /** + * 查询所有我可以发起的表单组 + * @return + */ + @GetMapping("listCurrentUserStartGroup") + public R listCurrentUserStartGroup() { + return combinationGroupService.listCurrentUserStartGroup(); + } + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/controller/OrgController.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/controller/OrgController.java new file mode 100644 index 000000000..2d58bc84c --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/controller/OrgController.java @@ -0,0 +1,44 @@ +package com.pig4cloud.pigx.flow.task.controller; + +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.task.service.IOrgService; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author : willian fu + * @date : 2022/6/27 + */ +@RestController +@RequiredArgsConstructor +@RequestMapping("/org") +public class OrgController { + + private final IOrgService orgService; + + /** + * 查询组织架构树 + * @param deptId 部门id + * @param showLeave 是否显示离职员工 + * @return 组织架构树数据 + */ + @GetMapping("tree") + public R getOrgTreeData(@RequestParam(defaultValue = "0") Long deptId, String type, + @RequestParam(defaultValue = "false") Boolean showLeave) { + return orgService.getOrgTreeData(deptId, type, showLeave); + } + + /** + * 模糊搜索用户 + * @param userName 用户名/拼音/首字母 + * @return 匹配到的用户 + */ + @GetMapping("tree/user/search") + public R getOrgTreeUser(@RequestParam String userName) { + return orgService.getOrgTreeUser(userName.trim()); + } + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/controller/ProcessController.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/controller/ProcessController.java new file mode 100644 index 000000000..644522bcc --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/controller/ProcessController.java @@ -0,0 +1,49 @@ +package com.pig4cloud.pigx.flow.task.controller; + +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.task.entity.Process; +import com.pig4cloud.pigx.flow.task.service.IProcessService; +import com.pig4cloud.pigx.flow.task.vo.ProcessVO; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/process") +public class ProcessController { + + private final IProcessService processService; + + /** + * 获取详细数据 + * @param flowId + * @return + */ + @GetMapping("getDetail") + public R getDetail(String flowId) { + return processService.getDetail(flowId); + } + + /** + * 创建流程 + * @param process + * @return + */ + @PostMapping("create") + public R create(@RequestBody Process process) { + return processService.create(process); + } + + /** + * 编辑表单 + * @param flowId 摸板ID + * @param type 类型 stop using delete + * @return 操作结果 + */ + @PutMapping("update/{flowId}") + public R update(@PathVariable String flowId, @RequestParam String type, + @RequestParam(required = false) Long groupId) { + return processService.update(flowId, type, groupId); + } + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/controller/ProcessCopyController.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/controller/ProcessCopyController.java new file mode 100644 index 000000000..19d2362a0 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/controller/ProcessCopyController.java @@ -0,0 +1,35 @@ +package com.pig4cloud.pigx.flow.task.controller; + +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.task.service.IProcessCopyService; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + *

+ * 流程抄送数据 前端控制器 + *

+ * + * @author Vincent + * @since 2023-05-20 + */ +@RestController +@RequiredArgsConstructor +@RequestMapping("/processCopy") +public class ProcessCopyController { + + private final IProcessCopyService processCopyService; + + /** + * 查询单个抄送详细信息 + * @param id + * @return + */ + @GetMapping("querySingleDetail") + public R querySingleDetail(long id) { + return processCopyService.querySingleDetail(id); + } + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/controller/ProcessGroupController.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/controller/ProcessGroupController.java new file mode 100644 index 000000000..70e0a878f --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/controller/ProcessGroupController.java @@ -0,0 +1,47 @@ +package com.pig4cloud.pigx.flow.task.controller; + +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.task.entity.ProcessGroup; +import com.pig4cloud.pigx.flow.task.service.IProcessGroupService; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequiredArgsConstructor +@RequestMapping("processGroup") +public class ProcessGroupController { + + private final IProcessGroupService processGroupService; + + /** + * 组列表 + * @return + */ + @GetMapping("list") + public R> queryList() { + return processGroupService.queryList(); + } + + /** + * 新增流程分组 + * @param processGroup 分组名 + * @return 添加结果 + */ + @PostMapping("create") + public R create(@RequestBody ProcessGroup processGroup) { + return processGroupService.create(processGroup); + } + + /** + * 删除分组 + * @param id + * @return + */ + @DeleteMapping("delete/{id}") + public R delete(@PathVariable long id) { + return processGroupService.delete(id); + } + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/controller/ProcessInstanceController.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/controller/ProcessInstanceController.java new file mode 100644 index 000000000..b9024b518 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/controller/ProcessInstanceController.java @@ -0,0 +1,109 @@ +package com.pig4cloud.pigx.flow.task.controller; + +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.task.dto.ProcessInstanceParamDto; +import com.pig4cloud.pigx.flow.task.dto.TaskQueryParamDto; +import com.pig4cloud.pigx.flow.task.service.IProcessInstanceService; +import com.pig4cloud.pigx.flow.task.vo.NodeFormatParamVo; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import org.springframework.web.bind.annotation.*; + +/** + * 流程实例 + */ +@RestController +@RequiredArgsConstructor +@RequestMapping("/process-instance") +public class ProcessInstanceController { + + private final IProcessInstanceService processInstanceService; + + /** + * 启动流程 + * @param processInstanceParamDto + * @return + */ + @SneakyThrows + @PostMapping("startProcessInstance") + public R startProcessInstance(@RequestBody ProcessInstanceParamDto processInstanceParamDto) { + return processInstanceService.startProcessInstance(processInstanceParamDto); + } + + /** + * 查询当前登录用户的待办任务 + * @param pageDto + * @return + */ + @SneakyThrows + @PostMapping("queryMineTask") + public R queryMineTask(@RequestBody TaskQueryParamDto queryParamDto) { + return processInstanceService.queryMineTask(queryParamDto); + } + + /** + * 查询当前登录用户已办任务 + * @param taskQueryParamDto + * @return + */ + @SneakyThrows + @PostMapping("queryMineEndTask") + public R queryMineEndTask(@RequestBody TaskQueryParamDto taskQueryParamDto) { + return processInstanceService.queryMineEndTask(taskQueryParamDto); + } + + /** + * 查询我发起的 + * @param pageDto + * @return + */ + @SneakyThrows + @PostMapping("queryMineStarted") + public R queryMineStarted(@RequestBody TaskQueryParamDto taskQueryParamDto) { + return processInstanceService.queryMineStarted(taskQueryParamDto); + } + + /** + * 查询抄送我的 + * @param pageDto + * @return + */ + @SneakyThrows + @PostMapping("queryMineCC") + public R queryMineCC(@RequestBody TaskQueryParamDto taskQueryParamDto) { + return processInstanceService.queryMineCC(taskQueryParamDto); + } + + /** + * 显示流程图 + * @param procInsId + * @return + */ + + @SneakyThrows + @GetMapping("showImg") + public R showImg(String procInsId) { + return processInstanceService.showImg(procInsId); + } + + /** + * 格式化流程显示 + * @param nodeFormatParamVo + * @return + */ + @PostMapping("formatStartNodeShow") + public R formatStartNodeShow(@RequestBody NodeFormatParamVo nodeFormatParamVo) { + return processInstanceService.formatStartNodeShow(nodeFormatParamVo); + } + + /** + * 流程详情 + * @param processInstanceId + * @return + */ + @GetMapping("detail") + public R detail(String processInstanceId) { + return processInstanceService.detail(processInstanceId); + } + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/controller/ProcessNodeDataController.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/controller/ProcessNodeDataController.java new file mode 100644 index 000000000..2a5d6dce9 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/controller/ProcessNodeDataController.java @@ -0,0 +1,46 @@ +package com.pig4cloud.pigx.flow.task.controller; + +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.task.dto.Node; +import com.pig4cloud.pigx.flow.task.dto.ProcessNodeDataDto; +import com.pig4cloud.pigx.flow.task.service.IProcessNodeDataService; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +/** + *

+ * 流程节点数据 前端控制器 + *

+ * + * @author Vincent + * @since 2023-05-07 + */ +@RestController +@RequiredArgsConstructor +@RequestMapping("/processNodeData") +public class ProcessNodeDataController { + + private final IProcessNodeDataService processNodeDataService; + + /** + * 保存节点数据 + * @param processNodeDataDto + * @return + */ + @PostMapping("saveNodeData") + public R saveNodeData(@RequestBody ProcessNodeDataDto processNodeDataDto) { + return processNodeDataService.saveNodeData(processNodeDataDto); + } + + /** + * 获取节点数据 + * @param flowId + * @param nodeId + * @return + */ + @GetMapping("getNodeData") + public R getNodeData(String flowId, String nodeId) { + return processNodeDataService.getNodeData(flowId, nodeId); + } + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/controller/RemoteController.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/controller/RemoteController.java new file mode 100644 index 000000000..551a84ea8 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/controller/RemoteController.java @@ -0,0 +1,152 @@ +package com.pig4cloud.pigx.flow.task.controller; + +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.task.dto.*; +import com.pig4cloud.pigx.flow.task.service.IRemoteService; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +/** + * 远程请求控制器 + */ +@RestController +@RequiredArgsConstructor +@RequestMapping("/remote") +public class RemoteController { + + private final IRemoteService remoteService; + + /** + * 根据角色id集合查询用户id集合 + * @param roleIdList + * @return + */ + @PostMapping("queryUserIdListByRoleIdList") + public R> queryUserIdListByRoleIdList(@RequestBody List roleIdList) { + return remoteService.queryUserIdListByRoleIdList(roleIdList); + } + + /** + * 保存抄送 + * @param copyDto + * @return + */ + @PostMapping("savecc") + public R saveCC(@RequestBody ProcessCopyDto copyDto) { + return remoteService.saveCC(copyDto); + } + + /** + * 检查是否是所有的父级 + * @param checkParentDto + * @return + */ + @PostMapping("checkIsAllParent") + public R checkIsAllParent(@RequestBody CheckParentDto checkParentDto) { + return remoteService.checkIsAllParent(checkParentDto); + } + + /** + * 根据部门id集合查询用户id集合 + * @param depIdList + * @return + */ + @PostMapping("queryUserIdListByDepIdList") + public R> queryUserIdListByDepIdList(@RequestBody List depIdList) { + return remoteService.queryUserIdListByDepIdList(depIdList); + } + + /** + * 检查是否是所有的子级 + * @param checkChildDto + * @return + */ + @PostMapping("checkIsAllChild") + public R checkIsAllChild(@RequestBody CheckChildDto checkChildDto) { + return remoteService.checkIsAllChild(checkChildDto); + } + + /** + * 获取用户的信息-包括扩展字段 + * @param userId + * @return + */ + @GetMapping("queryUserAllInfo") + public R> queryUserAllInfo(long userId) { + return remoteService.queryUserAllInfo(userId); + } + + /** + * 开始节点事件 + * @param recordParamDto + * @return + */ + @PostMapping("startNodeEvent") + public R startNodeEvent(@RequestBody ProcessNodeRecordParamDto recordParamDto) { + return remoteService.startNodeEvent(recordParamDto); + } + + /** + * 流程创建了 + * @param processInstanceRecordParamDto + * @return + */ + @PostMapping("createProcessEvent") + public R createProcessEvent(@RequestBody ProcessInstanceRecordParamDto processInstanceRecordParamDto) { + return remoteService.createProcessEvent(processInstanceRecordParamDto); + } + + /** + * 结束节点事件 + * @param recordParamDto + * @return + */ + @PostMapping("endNodeEvent") + public R endNodeEvent(@RequestBody ProcessNodeRecordParamDto recordParamDto) { + return remoteService.endNodeEvent(recordParamDto); + } + + /** + * 开始设置执行人 + * @param processNodeRecordAssignUserParamDto + * @return + */ + @PostMapping("startAssignUser") + public R startAssignUser(@RequestBody ProcessNodeRecordAssignUserParamDto processNodeRecordAssignUserParamDto) { + return remoteService.startAssignUser(processNodeRecordAssignUserParamDto); + } + + /** + * 任务结束事件 + * @param processNodeRecordAssignUserParamDto + * @return + */ + @PostMapping("taskEndEvent") + public R taskEndEvent(@RequestBody ProcessNodeRecordAssignUserParamDto processNodeRecordAssignUserParamDto) { + return remoteService.taskEndEvent(processNodeRecordAssignUserParamDto); + } + + /** + * 实例结束 + * @param processInstanceParamDto + * @return + */ + @PostMapping("endProcess") + public R endProcess(@RequestBody ProcessInstanceParamDto processInstanceParamDto) { + return remoteService.endProcess(processInstanceParamDto.getProcessInstanceId()); + } + + /** + * 查询流程管理员 + * @param flowId + * @return + */ + @GetMapping("queryProcessAdmin") + public R queryProcessAdmin(String flowId) { + return remoteService.queryProcessAdmin(flowId); + } + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/controller/TaskController.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/controller/TaskController.java new file mode 100644 index 000000000..4aebfb375 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/controller/TaskController.java @@ -0,0 +1,108 @@ +package com.pig4cloud.pigx.flow.task.controller; + +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.task.dto.TaskParamDto; +import com.pig4cloud.pigx.flow.task.service.ITaskService; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import org.springframework.web.bind.annotation.*; + +/** + * 任务实例 + */ +@RestController +@RequiredArgsConstructor +@RequestMapping("/task") +public class TaskController { + + private final ITaskService taskService; + + /** + * 查询任务 + * @param taskId + * @return + */ + @SneakyThrows + @GetMapping("queryTask") + public R queryTask(String taskId, boolean view) { + + return taskService.queryTask(taskId, view); + + } + + /** + * 完成任务 + * @param completeParamDto + * @return + */ + @SneakyThrows + @PostMapping("completeTask") + public R completeTask(@RequestBody TaskParamDto completeParamDto) { + + return taskService.completeTask(completeParamDto); + + } + + /** + * 前加签 + * @param completeParamDto + * @return + */ + @SneakyThrows + @PostMapping("delegateTask") + public R delegateTask(@RequestBody TaskParamDto completeParamDto) { + + return taskService.delegateTask(completeParamDto); + + } + + /** + * 加签完成任务 + * @param completeParamDto + * @return + */ + @SneakyThrows + @PostMapping("resolveTask") + public R resolveTask(@RequestBody TaskParamDto completeParamDto) { + + return taskService.resolveTask(completeParamDto); + + } + + /** + * 设置执行人 + * @param completeParamDto + * @return + */ + @SneakyThrows + @PostMapping("setAssignee") + public R setAssignee(@RequestBody TaskParamDto completeParamDto) { + + return taskService.setAssignee(completeParamDto); + + } + + /** + * 结束流程 + * @param completeParamDto + * @return + */ + @SneakyThrows + @PostMapping("stopProcessInstance") + public R stopProcessInstance(@RequestBody TaskParamDto completeParamDto) { + + return taskService.stopProcessInstance(completeParamDto); + + } + + /** + * 退回 + * @param taskParamDto + * @return + */ + @PostMapping("back") + public R back(@RequestBody TaskParamDto taskParamDto) { + return taskService.back(taskParamDto); + } + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/mapper/ProcessCopyMapper.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/mapper/ProcessCopyMapper.java new file mode 100644 index 000000000..db6b2d223 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/mapper/ProcessCopyMapper.java @@ -0,0 +1,18 @@ +package com.pig4cloud.pigx.flow.task.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.pig4cloud.pigx.flow.task.entity.ProcessCopy; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * 流程抄送数据 Mapper 接口 + *

+ * + * @author Vincent + * @since 2023-05-20 + */ +@Mapper +public interface ProcessCopyMapper extends BaseMapper { + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/mapper/ProcessGroupMapper.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/mapper/ProcessGroupMapper.java new file mode 100644 index 000000000..3b949c0e5 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/mapper/ProcessGroupMapper.java @@ -0,0 +1,18 @@ +package com.pig4cloud.pigx.flow.task.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.pig4cloud.pigx.flow.task.entity.ProcessGroup; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * Mapper 接口 + *

+ * + * @author Vincent + * @since 2023-05-25 + */ +@Mapper +public interface ProcessGroupMapper extends BaseMapper { + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/mapper/ProcessInstanceRecordMapper.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/mapper/ProcessInstanceRecordMapper.java new file mode 100644 index 000000000..b54d1fece --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/mapper/ProcessInstanceRecordMapper.java @@ -0,0 +1,18 @@ +package com.pig4cloud.pigx.flow.task.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.pig4cloud.pigx.flow.task.entity.ProcessInstanceRecord; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * 流程记录 Mapper 接口 + *

+ * + * @author Vincent + * @since 2023-05-07 + */ +@Mapper +public interface ProcessInstanceRecordMapper extends BaseMapper { + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/mapper/ProcessMapper.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/mapper/ProcessMapper.java new file mode 100644 index 000000000..06e7a9710 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/mapper/ProcessMapper.java @@ -0,0 +1,18 @@ +package com.pig4cloud.pigx.flow.task.mapper; + +import com.pig4cloud.pigx.flow.task.entity.Process; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * Mapper 接口 + *

+ * + * @author cxygzl + * @since 2023-05-25 + */ +@Mapper +public interface ProcessMapper extends BaseMapper { + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/mapper/ProcessNodeDataMapper.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/mapper/ProcessNodeDataMapper.java new file mode 100644 index 000000000..817977561 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/mapper/ProcessNodeDataMapper.java @@ -0,0 +1,18 @@ +package com.pig4cloud.pigx.flow.task.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.pig4cloud.pigx.flow.task.entity.ProcessNodeData; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * 流程节点数据 Mapper 接口 + *

+ * + * @author Vincent + * @since 2023-05-07 + */ +@Mapper +public interface ProcessNodeDataMapper extends BaseMapper { + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/mapper/ProcessNodeRecordAssignUserMapper.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/mapper/ProcessNodeRecordAssignUserMapper.java new file mode 100644 index 000000000..73cfbf26d --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/mapper/ProcessNodeRecordAssignUserMapper.java @@ -0,0 +1,18 @@ +package com.pig4cloud.pigx.flow.task.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.pig4cloud.pigx.flow.task.entity.ProcessNodeRecordAssignUser; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * 流程节点记录-执行人 Mapper 接口 + *

+ * + * @author cxygzl + * @since 2023-05-10 + */ +@Mapper +public interface ProcessNodeRecordAssignUserMapper extends BaseMapper { + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/mapper/ProcessNodeRecordMapper.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/mapper/ProcessNodeRecordMapper.java new file mode 100644 index 000000000..35acc48ff --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/mapper/ProcessNodeRecordMapper.java @@ -0,0 +1,18 @@ +package com.pig4cloud.pigx.flow.task.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.pig4cloud.pigx.flow.task.entity.ProcessNodeRecord; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * 流程节点记录 Mapper 接口 + *

+ * + * @author cxygzl + * @since 2023-05-10 + */ +@Mapper +public interface ProcessNodeRecordMapper extends BaseMapper { + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/mapper/ProcessStarterMapper.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/mapper/ProcessStarterMapper.java new file mode 100644 index 000000000..005e208a9 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/mapper/ProcessStarterMapper.java @@ -0,0 +1,18 @@ +package com.pig4cloud.pigx.flow.task.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.pig4cloud.pigx.flow.task.entity.ProcessStarter; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * 流程发起人 Mapper 接口 + *

+ * + * @author Vincent + * @since 2023-05-30 + */ +@Mapper +public interface ProcessStarterMapper extends BaseMapper { + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/ICombinationGroupService.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/ICombinationGroupService.java new file mode 100644 index 000000000..41155c026 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/ICombinationGroupService.java @@ -0,0 +1,24 @@ +package com.pig4cloud.pigx.flow.task.service; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.pig4cloud.pigx.common.core.util.R; + +/** + * 聚合接口 + */ +public interface ICombinationGroupService { + + /** + * 查询表单组包含流程 + * @param groupId 表单ID + * @return 表单组数据 + */ + R listGroupWithProcess(Page page, Long groupId); + + /** + * 查询所有我可以发起的表单组 + * @return + */ + R listCurrentUserStartGroup(); + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IOrgService.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IOrgService.java new file mode 100644 index 000000000..81cf342a7 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IOrgService.java @@ -0,0 +1,27 @@ +package com.pig4cloud.pigx.flow.task.service; + +import com.pig4cloud.pigx.common.core.util.R; + +/** + * @author : willian fu + * @version : 1.0 + */ +public interface IOrgService { + + /** + * 查询组织架构树 + * @param deptId 部门id + * @param type 只查询部门架构 + * @param showLeave 是否显示离职员工 + * @return 组织架构树数据 + */ + R getOrgTreeData(Long deptId, String type, Boolean showLeave); + + /** + * 模糊搜索用户 + * @param userName 用户名/拼音/首字母 + * @return 匹配到的用户 + */ + R getOrgTreeUser(String userName); + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IProcessCopyService.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IProcessCopyService.java new file mode 100644 index 000000000..ac181cb80 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IProcessCopyService.java @@ -0,0 +1,24 @@ +package com.pig4cloud.pigx.flow.task.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.task.entity.ProcessCopy; + +/** + *

+ * 流程抄送数据 服务类 + *

+ * + * @author Vincent + * @since 2023-05-20 + */ +public interface IProcessCopyService extends IService { + + /** + * 查询单个抄送详细信息 + * @param id + * @return + */ + R querySingleDetail(long id); + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IProcessGroupService.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IProcessGroupService.java new file mode 100644 index 000000000..1737f2a50 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IProcessGroupService.java @@ -0,0 +1,39 @@ +package com.pig4cloud.pigx.flow.task.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.task.entity.ProcessGroup; + +import java.util.List; + +/** + *

+ * 服务类 + *

+ * + * @author Vincent + * @since 2023-05-25 + */ +public interface IProcessGroupService extends IService { + + /** + * 组列表 + * @return + */ + R> queryList(); + + /** + * 新增流程分组 + * @param processGroup 分组名 + * @return 添加结果 + */ + R create(ProcessGroup processGroup); + + /** + * 删除分组 + * @param id + * @return + */ + R delete(long id); + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IProcessInstanceRecordService.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IProcessInstanceRecordService.java new file mode 100644 index 000000000..8e08978d8 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IProcessInstanceRecordService.java @@ -0,0 +1,16 @@ +package com.pig4cloud.pigx.flow.task.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.pig4cloud.pigx.flow.task.entity.ProcessInstanceRecord; + +/** + *

+ * 流程记录 服务类 + *

+ * + * @author Vincent + * @since 2023-05-07 + */ +public interface IProcessInstanceRecordService extends IService { + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IProcessInstanceService.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IProcessInstanceService.java new file mode 100644 index 000000000..0b0c0fd82 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IProcessInstanceService.java @@ -0,0 +1,76 @@ +package com.pig4cloud.pigx.flow.task.service; + +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.task.dto.ProcessInstanceParamDto; +import com.pig4cloud.pigx.flow.task.dto.TaskQueryParamDto; +import com.pig4cloud.pigx.flow.task.vo.NodeFormatParamVo; + +/** + * 流程实例进程 + */ +public interface IProcessInstanceService { + + /** + * 启动流程 + * @param processInstanceParamDto + * @return + */ + R startProcessInstance(ProcessInstanceParamDto processInstanceParamDto); + + /** + * 查询当前登录用户的待办任务 + * @param taskQueryParamDto taskQueryParamDto + * @return + */ + R queryMineTask(TaskQueryParamDto taskQueryParamDto); + + /** + * 查询已办任务 + * @param taskQueryParamDto + * @return + */ + R queryMineEndTask(TaskQueryParamDto taskQueryParamDto); + + /** + * 流程结束 + * @param processsInstanceId + * @return + */ + R end(String processsInstanceId); + + /** + * 查询我发起的 + * @param taskQueryParamDto + * @return + */ + R queryMineStarted(TaskQueryParamDto taskQueryParamDto); + + /** + * 查询抄送给我的 + * @param taskQueryParamDto + * @return + */ + R queryMineCC(TaskQueryParamDto taskQueryParamDto); + + /** + * 显示流程实例图片 + * @param procInsId + * @return + */ + R showImg(String procInsId); + + /** + * 格式化流程显示 + * @param nodeFormatParamVo + * @return + */ + R formatStartNodeShow(NodeFormatParamVo nodeFormatParamVo); + + /** + * 流程详情 + * @param processInstanceId + * @return + */ + R detail(String processInstanceId); + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IProcessNodeDataService.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IProcessNodeDataService.java new file mode 100644 index 000000000..76d1d62d8 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IProcessNodeDataService.java @@ -0,0 +1,34 @@ +package com.pig4cloud.pigx.flow.task.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.task.dto.Node; +import com.pig4cloud.pigx.flow.task.dto.ProcessNodeDataDto; +import com.pig4cloud.pigx.flow.task.entity.ProcessNodeData; + +/** + *

+ * 流程节点数据 服务类 + *

+ * + * @author Vincent + * @since 2023-05-07 + */ +public interface IProcessNodeDataService extends IService { + + /** + * 保存流程节点数据 + * @param processNodeDataDto + * @return + */ + R saveNodeData(ProcessNodeDataDto processNodeDataDto); + + /*** + * 获取节点数据 + * @param flowId + * @param nodeId + * @return + */ + R getNodeData(String flowId, String nodeId); + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IProcessNodeRecordAssignUserService.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IProcessNodeRecordAssignUserService.java new file mode 100644 index 000000000..eb718587e --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IProcessNodeRecordAssignUserService.java @@ -0,0 +1,32 @@ +package com.pig4cloud.pigx.flow.task.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.task.dto.ProcessNodeRecordAssignUserParamDto; +import com.pig4cloud.pigx.flow.task.entity.ProcessNodeRecordAssignUser; + +/** + *

+ * 流程节点记录-执行人 服务类 + *

+ * + * @author cxygzl + * @since 2023-05-10 + */ +public interface IProcessNodeRecordAssignUserService extends IService { + + /** + * 设置执行人 + * @param processNodeRecordAssignUserParamDto + * @return + */ + R addAssignUser(ProcessNodeRecordAssignUserParamDto processNodeRecordAssignUserParamDto); + + /** + * 任务完成通知 + * @param processNodeRecordAssignUserParamDto + * @return + */ + R completeTaskEvent(ProcessNodeRecordAssignUserParamDto processNodeRecordAssignUserParamDto); + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IProcessNodeRecordService.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IProcessNodeRecordService.java new file mode 100644 index 000000000..e27652fb9 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IProcessNodeRecordService.java @@ -0,0 +1,32 @@ +package com.pig4cloud.pigx.flow.task.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.task.dto.ProcessNodeRecordParamDto; +import com.pig4cloud.pigx.flow.task.entity.ProcessNodeRecord; + +/** + *

+ * 流程节点记录 服务类 + *

+ * + * @author cxygzl + * @since 2023-05-10 + */ +public interface IProcessNodeRecordService extends IService { + + /** + * 节点开始 + * @param processNodeRecordParamDto + * @return + */ + R start(ProcessNodeRecordParamDto processNodeRecordParamDto); + + /** + * 节点结束 + * @param processNodeRecordParamDto + * @return + */ + R complete(ProcessNodeRecordParamDto processNodeRecordParamDto); + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IProcessService.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IProcessService.java new file mode 100644 index 000000000..aabfe61ff --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IProcessService.java @@ -0,0 +1,46 @@ +package com.pig4cloud.pigx.flow.task.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.task.vo.ProcessVO; +import com.pig4cloud.pigx.flow.task.entity.Process; + +/** + *

+ * 服务类 + *

+ * + * @author cxygzl + * @since 2023-05-25 + */ +public interface IProcessService extends IService { + + /** + * 获取详细数据 + * @param flowId + * @return + */ + R getDetail(String flowId); + + Process getByFlowId(String flowId); + + void updateByFlowId(Process process); + + void hide(String flowId); + + /** + * 创建流程 + * @param process + * @return + */ + R create(Process process); + + /** + * 编辑表单 + * @param flowId 摸板ID + * @param type 类型 stop using delete + * @return 操作结果 + */ + R update(String flowId, String type, Long groupId); + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IProcessStarterService.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IProcessStarterService.java new file mode 100644 index 000000000..45f021b24 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IProcessStarterService.java @@ -0,0 +1,16 @@ +package com.pig4cloud.pigx.flow.task.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.pig4cloud.pigx.flow.task.entity.ProcessStarter; + +/** + *

+ * 流程发起人 服务类 + *

+ * + * @author Vincent + * @since 2023-05-30 + */ +public interface IProcessStarterService extends IService { + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IRemoteService.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IRemoteService.java new file mode 100644 index 000000000..1de7852bc --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/IRemoteService.java @@ -0,0 +1,106 @@ + +package com.pig4cloud.pigx.flow.task.service; + +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.task.dto.*; + +import java.util.List; +import java.util.Map; + +/** + * 远程调用的接口 + */ +public interface IRemoteService { + + /** + * 根据角色id集合查询用户id集合 + * @param roleIdList + * @return + */ + R> queryUserIdListByRoleIdList(List roleIdList); + + /** + * 保存抄送 + * @param copyDto + * @return + */ + R saveCC(ProcessCopyDto copyDto); + + /** + * 检查是否是所有的父级 + * @param checkParentDto + * @return + */ + R checkIsAllParent(CheckParentDto checkParentDto); + + /** + * 根据部门id集合查询用户id集合 + * @param depIdList + * @return + */ + R> queryUserIdListByDepIdList(List depIdList); + + /** + * 检查是否是所有的子级 + * @param checkChildDto + * @return + */ + R checkIsAllChild(CheckChildDto checkChildDto); + + /** + * 获取用户的信息-包括扩展字段 + * @param userId + * @return + */ + R> queryUserAllInfo(long userId); + + /** + * 开始节点事件 + * @param recordParamDto + * @return + */ + R startNodeEvent(ProcessNodeRecordParamDto recordParamDto); + + /** + * 流程创建了 + * @param processInstanceRecordParamDto + * @return + */ + R createProcessEvent(ProcessInstanceRecordParamDto processInstanceRecordParamDto); + + /** + * 完成节点事件 + * @param recordParamDto + * @return + */ + R endNodeEvent(ProcessNodeRecordParamDto recordParamDto); + + /** + * 开始设置执行人 + * @param processNodeRecordAssignUserParamDto + * @return + */ + R startAssignUser(ProcessNodeRecordAssignUserParamDto processNodeRecordAssignUserParamDto); + + /** + * 任务结束事件 + * @param processNodeRecordAssignUserParamDto + * @return + */ + R taskEndEvent(ProcessNodeRecordAssignUserParamDto processNodeRecordAssignUserParamDto); + + /** + * 实例结束 + * @param processInstanceId + * @return + */ + R endProcess(String processInstanceId); + + /** + * 查询流程管理员 + * @param flowId + * @return + */ + R queryProcessAdmin(String flowId); + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/ITaskService.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/ITaskService.java new file mode 100644 index 000000000..5917328a1 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/ITaskService.java @@ -0,0 +1,61 @@ +package com.pig4cloud.pigx.flow.task.service; + +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.task.dto.TaskParamDto; + +/** + * 任务处理 + */ +public interface ITaskService { + + /** + * 查询任务 + * @param taskId + * @param view + * @return + */ + R queryTask(String taskId, boolean view); + + /** + * 完成任务 + * @param taskParamDto + * @return + */ + R completeTask(TaskParamDto taskParamDto); + + /** + * 前加签 + * @param taskParamDto + * @return + */ + R delegateTask(TaskParamDto taskParamDto); + + /** + * 加签完成任务 + * @param taskParamDto + * @return + */ + R resolveTask(TaskParamDto taskParamDto); + + /** + * 设置执行人 + * @param taskParamDto + * @return + */ + R setAssignee(TaskParamDto taskParamDto); + + /** + * 结束流程 + * @param taskParamDto + * @return + */ + R stopProcessInstance(TaskParamDto taskParamDto); + + /** + * 退回 + * @param taskParamDto + * @return + */ + R back(TaskParamDto taskParamDto); + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/CombinationGroupServiceImpl.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/CombinationGroupServiceImpl.java new file mode 100644 index 000000000..99809d114 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/CombinationGroupServiceImpl.java @@ -0,0 +1,132 @@ +package com.pig4cloud.pigx.flow.task.service.impl; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.common.security.service.PigxUser; +import com.pig4cloud.pigx.common.security.util.SecurityUtils; +import com.pig4cloud.pigx.flow.task.constant.NodeUserTypeEnum; +import com.pig4cloud.pigx.flow.task.entity.Process; +import com.pig4cloud.pigx.flow.task.entity.ProcessGroup; +import com.pig4cloud.pigx.flow.task.entity.ProcessStarter; +import com.pig4cloud.pigx.flow.task.service.ICombinationGroupService; +import com.pig4cloud.pigx.flow.task.service.IProcessGroupService; +import com.pig4cloud.pigx.flow.task.service.IProcessService; +import com.pig4cloud.pigx.flow.task.service.IProcessStarterService; +import com.pig4cloud.pigx.flow.task.vo.FormGroupVo; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +@Service +@Slf4j +@RequiredArgsConstructor +public class CombinationGroupServiceImpl implements ICombinationGroupService { + + private final IProcessGroupService processGroupService; + + private final IProcessService processService; + + private final IProcessStarterService processStarterService; + + /** + * 查询表单组包含流程 + * @param hidden + * @return 表单组数据 + */ + @Override + public R listGroupWithProcess(Page page, Long groupId) { + return R.ok(processService.lambdaQuery() + .eq(Process::getGroupId, groupId) + .orderByAsc(Process::getSort) + .orderByDesc(Process::getCreateTime) + .page(page)); + } + + /** + * 查询所有我可以发起的表单组 + * @return + */ + @Override + public R listCurrentUserStartGroup() { + PigxUser user = SecurityUtils.getUser(); + + List formGroupVos = new LinkedList<>(); + + List processGroupList = processGroupService.lambdaQuery() + .orderByAsc(ProcessGroup::getSort) + .list(); + + processGroupList.forEach(group -> { + FormGroupVo formGroupVo = FormGroupVo.builder() + .id(group.getId()) + .name(group.getGroupName()) + .items(new LinkedList<>()) + .build(); + formGroupVos.add(formGroupVo); + + List processList = processService.lambdaQuery() + .eq(Process::getGroupId, group.getId()) + .eq(Process::getHidden, false) + .eq(Process::getStop, false) + .orderByAsc(Process::getSort) + .list(); + + Map existMap = new HashMap<>(); + + if (!processList.isEmpty()) { + List idList = processList.stream().map(Process::getId).collect(Collectors.toList()); + // 查询发起人集合 + List processStarterList = processStarterService.lambdaQuery() + .in(ProcessStarter::getProcessId, idList) + .list(); + Map> groupmap = processStarterList.stream() + .collect(Collectors.groupingBy(ProcessStarter::getProcessId)); + + for (Process process : processList) { + List processStarters = groupmap.get(process.getId()); + if (processStarters == null) { + existMap.put(process.getId(), true); + continue; + } + boolean match = processStarters.stream() + .anyMatch(w -> w.getTypeId().longValue() == user.getId() + && w.getType().equals(NodeUserTypeEnum.USER.getKey())); + if (match) { + existMap.put(process.getId(), true); + continue; + } + Set deptIdSet = processStarters.stream() + .filter(w -> w.getType().equals(NodeUserTypeEnum.DEPT.getKey())) + .map(w -> w.getTypeId()) + .collect(Collectors.toSet()); + + existMap.put(process.getId(), deptIdSet.contains(user.getDeptId())); + + } + + } + + processList.forEach(process -> { + + if (!existMap.get(process.getId())) { + return; + } + + formGroupVo.getItems() + .add(FormGroupVo.FlowVo.builder() + .flowId(process.getFlowId()) + .name(process.getName()) + .logo(process.getLogo()) + .remark(process.getRemark()) + .stop(process.getStop()) + .updated(process.getUpdateTime()) + .build()); + }); + }); + return R.ok(formGroupVos); + } + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/OrgServiceImpl.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/OrgServiceImpl.java new file mode 100644 index 000000000..08b5c4352 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/OrgServiceImpl.java @@ -0,0 +1,139 @@ +package com.pig4cloud.pigx.flow.task.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Dict; +import cn.hutool.core.util.StrUtil; +import com.pig4cloud.pigx.admin.api.entity.SysDept; +import com.pig4cloud.pigx.admin.api.entity.SysRole; +import com.pig4cloud.pigx.admin.api.entity.SysUser; +import com.pig4cloud.pigx.admin.api.feign.RemoteDeptService; +import com.pig4cloud.pigx.admin.api.feign.RemoteRoleService; +import com.pig4cloud.pigx.admin.api.feign.RemoteUserService; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.common.core.util.RetOps; +import com.pig4cloud.pigx.flow.task.constant.NodeUserTypeEnum; +import com.pig4cloud.pigx.flow.task.service.IOrgService; +import com.pig4cloud.pigx.flow.task.utils.DataUtil; +import com.pig4cloud.pigx.flow.task.vo.OrgTreeVo; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class OrgServiceImpl implements IOrgService { + + private final RemoteUserService remoteUserService; + + private final RemoteRoleService remoteRoleService; + + private final RemoteDeptService remoteDeptService; + + /** + * 查询组织架构树 + * @param deptId 部门id + * @param type 只查询部门架构 + * @param showLeave 是否显示离职员工 + * @return 组织架构树数据 + */ + @Override + public R getOrgTreeData(Long deptId, String type, Boolean showLeave) { + List orgs = new LinkedList<>(); + + if (StrUtil.equals(type, NodeUserTypeEnum.ROLE.getKey())) { + // 角色 + + List roleList = remoteRoleService.getAllRole().getData(); + + for (SysRole role : roleList) { + OrgTreeVo orgTreeVo = new OrgTreeVo(); + orgTreeVo.setId(role.getRoleId()); + orgTreeVo.setName(role.getRoleName()); + orgTreeVo.setType(NodeUserTypeEnum.ROLE.getKey()); + orgTreeVo.setSelected(false); + orgs.add(orgTreeVo); + } + + Dict dict = Dict.create() + .set("roleList", orgs) + .set("childDepartments", orgs) + .set("employees", new ArrayList<>()); + return R.ok(dict); + + } + + Dict dict = Dict.create() + .set("titleDepartments", new ArrayList<>()) + .set("roleList", new ArrayList<>()) + .set("employees", new ArrayList<>()); + + List deptList = remoteDeptService.getAllDept().getData(); + + // 查询所有部门及员工 + { + List deptVoList = new ArrayList(); + for (SysDept dept : deptList) { + OrgTreeVo orgTreeVo = new OrgTreeVo(); + orgTreeVo.setId(dept.getDeptId()); + orgTreeVo.setName(dept.getName()); + orgTreeVo.setType(NodeUserTypeEnum.DEPT.getKey()); + orgTreeVo.setSelected(false); + deptVoList.add(orgTreeVo); + } + dict.set("childDepartments", deptVoList); + } + if (!StrUtil.equals(type, NodeUserTypeEnum.DEPT.getKey())) { + + List userVoList = new ArrayList(); + + List userList = remoteUserService.getUserIdListByDeptIdList(CollUtil.toList(deptId)).getData(); + + for (SysUser user : userList) { + OrgTreeVo orgTreeVo = new OrgTreeVo(); + orgTreeVo.setId(user.getUserId()); + orgTreeVo.setName(user.getUsername()); + orgTreeVo.setType(NodeUserTypeEnum.USER.getKey()); + orgTreeVo.setSelected(false); + orgTreeVo.setAvatar(user.getAvatar()); + userVoList.add(orgTreeVo); + } + dict.set("employees", userVoList); + } + + if (deptId > 0) { + List allDept = remoteDeptService.getAllDept().getData(); + List depts = DataUtil.selectParentByDept(deptId, allDept); + dict.set("titleDepartments", CollUtil.reverse(depts)); + } + + return R.ok(dict); + } + + /** + * 模糊搜索用户 + * @param userName 用户名/拼音/首字母 + * @return 匹配到的用户 + */ + @Override + public R getOrgTreeUser(String userName) { + return R.ok(RetOps.of(remoteUserService.getUserListByUserName(userName)) + .getData() + .orElseGet(ArrayList::new) + .stream() + .map(user -> { + OrgTreeVo orgTreeVo = new OrgTreeVo(); + orgTreeVo.setId(user.getUserId()); + orgTreeVo.setName(user.getUsername()); + orgTreeVo.setType(NodeUserTypeEnum.USER.getKey()); + orgTreeVo.setSelected(false); + orgTreeVo.setAvatar(user.getAvatar()); + return orgTreeVo; + }) + .collect(Collectors.toList())); + } + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/ProcessCopyServiceImpl.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/ProcessCopyServiceImpl.java new file mode 100644 index 000000000..40daf692e --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/ProcessCopyServiceImpl.java @@ -0,0 +1,117 @@ +package com.pig4cloud.pigx.flow.task.service.impl; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.Dict; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.TypeReference; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.task.constant.FormTypeEnum; +import com.pig4cloud.pigx.flow.task.constant.ProcessInstanceConstant; +import com.pig4cloud.pigx.flow.task.dto.Node; +import com.pig4cloud.pigx.flow.task.entity.Process; +import com.pig4cloud.pigx.flow.task.entity.ProcessCopy; +import com.pig4cloud.pigx.flow.task.mapper.ProcessCopyMapper; +import com.pig4cloud.pigx.flow.task.service.IProcessCopyService; +import com.pig4cloud.pigx.flow.task.service.IProcessNodeDataService; +import com.pig4cloud.pigx.flow.task.service.IProcessService; +import com.pig4cloud.pigx.flow.task.vo.FormItemVO; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + *

+ * 流程抄送数据 服务实现类 + *

+ * + * @author Vincent + * @since 2023-05-20 + */ +@Service +@RequiredArgsConstructor +public class ProcessCopyServiceImpl extends ServiceImpl implements IProcessCopyService { + + private final IProcessService processService; + + private final IProcessNodeDataService nodeDataService; + + /** + * 查询单个抄送详细信息 + * @param id + * @return + */ + @Override + public R querySingleDetail(long id) { + ProcessCopy processCopy = this.getById(id); + String flowId = processCopy.getFlowId(); + Process oaForms = processService.getByFlowId(flowId); + if (oaForms == null) { + return R.failed("流程不存在"); + } + String formData = processCopy.getFormData(); + + Map variableMap = JSON.parseObject(formData, new TypeReference<>() { + }); + + String nodeId = processCopy.getNodeId(); + + Node node = nodeDataService.getNodeData(flowId, nodeId).getData(); + Map formPerms = node.getFormPerms(); + + List jsonObjectList = JSON.parseArray(oaForms.getFormItems(), FormItemVO.class); + for (FormItemVO formItemVO : jsonObjectList) { + String fid = formItemVO.getId(); + String perm = formPerms.get(fid); + formItemVO.setPerm(StrUtil.isBlankIfStr(perm) ? ProcessInstanceConstant.FormPermClass.HIDE : perm); + + if (formItemVO.getType().equals(FormTypeEnum.LAYOUT.getType())) { + // 明细 + + List> subParamList = MapUtil.get(variableMap, fid, + new cn.hutool.core.lang.TypeReference>>() { + }); + + Object value = formItemVO.getProps().getValue(); + + List> l = new ArrayList<>(); + for (Map map : subParamList) { + List subItemList = Convert.toList(FormItemVO.class, value); + for (FormItemVO itemVO : subItemList) { + itemVO.getProps().setValue(map.get(itemVO.getId())); + + String permSub = formPerms.get(itemVO.getId()); + if (StrUtil.isNotBlank(permSub)) { + itemVO.setPerm(ProcessInstanceConstant.FormPermClass.EDIT.equals(permSub) + ? ProcessInstanceConstant.FormPermClass.READ : permSub + + ); + + } + else { + itemVO.setPerm(ProcessInstanceConstant.FormPermClass.HIDE); + } + + } + l.add(subItemList); + } + formItemVO.getProps().setValue(l); + + } + else { + formItemVO.getProps().setValue(variableMap.get(fid)); + + } + + } + Dict set = Dict.create().set("formItems", jsonObjectList); + + return R.ok(set); + } + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/ProcessGroupServiceImpl.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/ProcessGroupServiceImpl.java new file mode 100644 index 000000000..b8e48d8de --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/ProcessGroupServiceImpl.java @@ -0,0 +1,61 @@ +package com.pig4cloud.pigx.flow.task.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.task.entity.ProcessGroup; +import com.pig4cloud.pigx.flow.task.mapper.ProcessGroupMapper; +import com.pig4cloud.pigx.flow.task.service.IProcessGroupService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + *

+ * 服务实现类 + *

+ * + * @author Vincent + * @since 2023-05-25 + */ +@Service +public class ProcessGroupServiceImpl extends ServiceImpl + implements IProcessGroupService { + + /** + * 组列表 + * @return + */ + @Override + public R> queryList() { + List processGroupList = this.lambdaQuery().orderByAsc(ProcessGroup::getSort).list(); + + return R.ok(processGroupList); + } + + /** + * 新增表单分组 + * @param processGroup 分组名 + * @return 添加结果 + */ + @Override + public R create(ProcessGroup processGroup) { + ProcessGroup pg = new ProcessGroup(); + pg.setSort(0); + pg.setGroupName(processGroup.getGroupName()); + + this.save(pg); + return R.ok(); + } + + /** + * 删除分组 + * @param id + * @return + */ + @Override + public R delete(long id) { + this.removeById(id); + return R.ok(); + } + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/ProcessInstanceRecordServiceImpl.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/ProcessInstanceRecordServiceImpl.java new file mode 100644 index 000000000..9cc962709 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/ProcessInstanceRecordServiceImpl.java @@ -0,0 +1,21 @@ +package com.pig4cloud.pigx.flow.task.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.pig4cloud.pigx.flow.task.entity.ProcessInstanceRecord; +import com.pig4cloud.pigx.flow.task.mapper.ProcessInstanceRecordMapper; +import com.pig4cloud.pigx.flow.task.service.IProcessInstanceRecordService; +import org.springframework.stereotype.Service; + +/** + *

+ * 流程记录 服务实现类 + *

+ * + * @author Vincent + * @since 2023-05-07 + */ +@Service +public class ProcessInstanceRecordServiceImpl extends ServiceImpl + implements IProcessInstanceRecordService { + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/ProcessInstanceServiceImpl.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/ProcessInstanceServiceImpl.java new file mode 100644 index 000000000..9c09bc90e --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/ProcessInstanceServiceImpl.java @@ -0,0 +1,448 @@ +package com.pig4cloud.pigx.flow.task.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.Dict; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.TypeReference; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.pig4cloud.pigx.admin.api.entity.SysUser; +import com.pig4cloud.pigx.admin.api.feign.RemoteUserService; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.common.security.service.PigxUser; +import com.pig4cloud.pigx.common.security.util.SecurityUtils; +import com.pig4cloud.pigx.flow.task.api.feign.RemoteFlowEngineService; +import com.pig4cloud.pigx.flow.task.constant.FormTypeEnum; +import com.pig4cloud.pigx.flow.task.constant.NodeStatusEnum; +import com.pig4cloud.pigx.flow.task.constant.NodeUserTypeEnum; +import com.pig4cloud.pigx.flow.task.constant.ProcessInstanceConstant; +import com.pig4cloud.pigx.flow.task.dto.*; +import com.pig4cloud.pigx.flow.task.entity.Process; +import com.pig4cloud.pigx.flow.task.entity.ProcessCopy; +import com.pig4cloud.pigx.flow.task.entity.ProcessInstanceRecord; +import com.pig4cloud.pigx.flow.task.entity.ProcessNodeRecord; +import com.pig4cloud.pigx.flow.task.entity.ProcessNodeRecordAssignUser; +import com.pig4cloud.pigx.flow.task.service.*; +import com.pig4cloud.pigx.flow.task.utils.NodeFormatUtil; +import com.pig4cloud.pigx.flow.task.vo.FormItemVO; +import com.pig4cloud.pigx.flow.task.vo.NodeFormatParamVo; +import com.pig4cloud.pigx.flow.task.vo.ProcessCopyVo; +import com.pig4cloud.pigx.flow.task.vo.NodeVo; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 实例进程服务 + */ +@Service +@Slf4j +@RequiredArgsConstructor +public class ProcessInstanceServiceImpl implements IProcessInstanceService { + + private final RemoteFlowEngineService flowEngineService; + + private final RemoteUserService userService; + + private final IProcessInstanceRecordService processInstanceRecordService; + + private final IProcessCopyService processCopyService; + + private final IProcessService processService; + + private final IProcessNodeRecordService processNodeRecordService; + + private final IProcessNodeRecordAssignUserService processNodeRecordAssignUserService; + + /** + * 启动流程 + * @param processInstanceParamDto + * @return + */ + @Override + public R startProcessInstance(ProcessInstanceParamDto processInstanceParamDto) { + + PigxUser user = SecurityUtils.getUser(); + + processInstanceParamDto.setStartUserId(String.valueOf(user.getId())); + Map paramMap = processInstanceParamDto.getParamMap(); + Dict rootUser = Dict.create() + .set("id", user.getId()) + .set("name", user.getUsername()) + .set("type", NodeUserTypeEnum.USER.getKey()); + paramMap.put("root", CollUtil.newArrayList(rootUser)); + return flowEngineService.startProcess(processInstanceParamDto); + } + + /** + * 查询当前登录用户的待办任务 + * @param pageVO + * @param taskDto + * @return + */ + @Override + public R queryMineTask(TaskQueryParamDto taskQueryParamDto) { + taskQueryParamDto.setAssign(SecurityUtils.getUser().getId().toString()); + R> r = flowEngineService.queryAssignTask(taskQueryParamDto); + + if (CollUtil.isEmpty(r.getData().getRecords())) { + return r; + } + + Set processInstanceIdSet = r.getData() + .getRecords() + .stream() + .map(TaskDto::getProcessInstanceId) + .collect(Collectors.toSet()); + + // 流程实例记录 + List processInstanceRecordList = processInstanceRecordService.lambdaQuery() + .in(ProcessInstanceRecord::getProcessInstanceId, processInstanceIdSet) + .list(); + + // 发起人 + List startUserList = processInstanceRecordList.stream() + .map(ProcessInstanceRecord::getUserId) + .map(userId -> userService.getUserById(userId).getData()) + .toList(); + + Page pageResultDto = r.getData(); + List taskDtoList = new ArrayList<>(); + for (TaskDto record : r.getData().getRecords()) { + ProcessInstanceRecord processInstanceRecord = processInstanceRecordList.stream() + .filter(w -> StrUtil.equals(w.getProcessInstanceId(), record.getProcessInstanceId())) + .findAny() + .orElse(null); + + if (processInstanceRecord != null) { + record.setProcessName(processInstanceRecord.getName()); + SysUser startUser = startUserList.stream() + .filter(w -> w.getUserId().longValue() == processInstanceRecord.getUserId()) + .findAny() + .orElse(null); + + record.setRootUserId(processInstanceRecord.getUserId()); + record.setGroupName(processInstanceRecord.getGroupName()); + record.setRootUserName(startUser.getUsername()); + record.setRootUserAvatarUrl(startUser.getAvatar()); + record.setStartTime(processInstanceRecord.getCreateTime()); + + taskDtoList.add(record); + } + } + + pageResultDto.setRecords(taskDtoList); + + return R.ok(pageResultDto); + } + + /** + * 查询已办任务 + * @param taskQueryParamDto + * @return + */ + @Override + public R queryMineEndTask(TaskQueryParamDto taskQueryParamDto) { + taskQueryParamDto.setAssign(SecurityUtils.getUser().getId().toString()); + R> r = flowEngineService.queryCompletedTask(taskQueryParamDto); + + Page pageResultDto = r.getData(); + List records = pageResultDto.getRecords(); + if (CollUtil.isEmpty(records)) { + return R.ok(pageResultDto); + + } + + Set processInstanceIdSet = records.stream() + .map(TaskDto::getProcessInstanceId) + .collect(Collectors.toSet()); + + // 流程实例记录 + List processInstanceRecordList = processInstanceRecordService.lambdaQuery() + .in(ProcessInstanceRecord::getProcessInstanceId, processInstanceIdSet) + .list(); + + // 发起人 + List startUserList = processInstanceRecordList.stream() + .map(ProcessInstanceRecord::getUserId) + .map(userId -> userService.getUserById(userId).getData()) + .toList(); + + List taskDtoList = new ArrayList<>(); + for (TaskDto record : records) { + + ProcessInstanceRecord processInstanceRecord = processInstanceRecordList.stream() + .filter(w -> StrUtil.equals(w.getProcessInstanceId(), record.getProcessInstanceId())) + .findAny() + .orElse(null); + + if (processInstanceRecord != null) { + + record.setProcessName(processInstanceRecord.getName()); + + SysUser startUser = startUserList.stream() + .filter(w -> w.getUserId().longValue() == processInstanceRecord.getUserId()) + .findAny() + .orElse(null); + + record.setRootUserId(processInstanceRecord.getUserId()); + record.setGroupName(processInstanceRecord.getGroupName()); + record.setRootUserName(startUser.getName()); + record.setRootUserAvatarUrl(startUser.getAvatar()); + record.setTaskId(record.getTaskId()); + record.setStartTime(processInstanceRecord.getCreateTime()); + taskDtoList.add(record); + } + } + + pageResultDto.setRecords(taskDtoList); + + return R.ok(pageResultDto); + } + + /** + * 流程结束 + * @param processsInstanceId + * @return + */ + @Override + public R end(String processsInstanceId) { + processInstanceRecordService.lambdaUpdate() + .set(ProcessInstanceRecord::getEndTime, new Date()) + .set(ProcessInstanceRecord::getStatus, NodeStatusEnum.YJS.getCode()) + .eq(ProcessInstanceRecord::getProcessInstanceId, processsInstanceId) + .update(new ProcessInstanceRecord()); + return R.ok(); + } + + /** + * 查询我发起的 + * @param pageDto + * @return + */ + @Override + public R queryMineStarted(TaskQueryParamDto taskQueryParamDto) { + + long userId = SecurityUtils.getUser().getId(); + + Page instanceRecordPage = processInstanceRecordService.lambdaQuery() + .eq(ProcessInstanceRecord::getUserId, userId) + .eq(ProcessInstanceRecord::getStatus, taskQueryParamDto.getStatus()) + .between(ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()), ProcessInstanceRecord::getCreateTime, + ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()) ? taskQueryParamDto.getTaskTime()[0] : null, + ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()) ? taskQueryParamDto.getTaskTime()[1] : null) + .orderByDesc(ProcessInstanceRecord::getCreateTime) + .page(new Page<>(taskQueryParamDto.getPageNum(), taskQueryParamDto.getPageSize())); + + return R.ok(instanceRecordPage); + } + + /** + * 查询抄送给我的 + * @param pageDto + * @return + */ + @Override + public R queryMineCC(TaskQueryParamDto taskQueryParamDto) { + + long userId = SecurityUtils.getUser().getId(); + + Page page = processCopyService.lambdaQuery() + .eq(ProcessCopy::getUserId, userId) + .between(ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()), ProcessCopy::getCreateTime, + ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()) ? taskQueryParamDto.getTaskTime()[0] : null, + ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()) ? taskQueryParamDto.getTaskTime()[1] : null) + .orderByDesc(ProcessCopy::getNodeTime) + .page(new Page<>(taskQueryParamDto.getPageNum(), taskQueryParamDto.getPageSize())); + + List records = page.getRecords(); + + List processCopyVoList = BeanUtil.copyToList(records, ProcessCopyVo.class); + + if (CollUtil.isNotEmpty(records)) { + // 发起人 + List startUserList = records.stream() + .map(ProcessCopy::getStartUserId) + .map(id -> userService.getUserById(id).getData()) + .toList(); + + for (ProcessCopyVo record : processCopyVoList) { + SysUser startUser = startUserList.stream() + .filter(w -> w.getUserId().longValue() == record.getStartUserId()) + .findAny() + .orElse(null); + record.setStartUserName(startUser.getUsername()); + } + } + + Page p = BeanUtil.copyProperties(page, Page.class); + + p.setRecords(processCopyVoList); + + return R.ok(p); + } + + /** + * 显示流程实例图片 + * @param procInsId + * @return + */ + @Override + public R showImg(String procInsId) { + return flowEngineService.showImg(procInsId); + } + + /** + * 格式化流程显示 + * @param nodeFormatParamVo + * @return + */ + @Override + public R formatStartNodeShow(NodeFormatParamVo nodeFormatParamVo) { + String flowId = nodeFormatParamVo.getFlowId(); + String processInstanceId = nodeFormatParamVo.getProcessInstanceId(); + if (StrUtil.isAllBlank(flowId, processInstanceId)) { + return R.ok(new ArrayList<>()); + } + + if (StrUtil.isBlankIfStr(flowId) && StrUtil.isNotBlank(processInstanceId)) { + ProcessInstanceRecord processInstanceRecord = processInstanceRecordService.lambdaQuery() + .eq(ProcessInstanceRecord::getProcessInstanceId, processInstanceId) + .one(); + flowId = processInstanceRecord.getFlowId(); + + } + Map paramMap = nodeFormatParamVo.getParamMap(); + if (StrUtil.isNotBlank(nodeFormatParamVo.getTaskId())) { + VariableQueryParamDto variableQueryParamDto = new VariableQueryParamDto(); + variableQueryParamDto.setTaskId(nodeFormatParamVo.getTaskId()); + R> r = flowEngineService.queryTaskVariables(variableQueryParamDto); + if (!r.isOk()) { + ProcessNodeRecordAssignUser processNodeRecordAssignUser = processNodeRecordAssignUserService + .lambdaQuery() + .eq(ProcessNodeRecordAssignUser::getTaskId, nodeFormatParamVo.getTaskId()) + .eq(ProcessNodeRecordAssignUser::getStatus, NodeStatusEnum.YJS.getCode()) + .last("limit 1") + .orderByDesc(ProcessNodeRecordAssignUser::getEndTime) + .one(); + + String data = processNodeRecordAssignUser.getData(); + Map variableMap = JSON.parseObject(data, new TypeReference<>() { + }); + variableMap.putAll(paramMap); + paramMap.putAll(variableMap); + } + else { + Map variableMap = r.getData(); + variableMap.putAll(paramMap); + paramMap.putAll(variableMap); + } + + } + + Set completeNodeSet = new HashSet<>(); + + if (StrUtil.isNotBlank(processInstanceId)) { + List processNodeRecordList = processNodeRecordService.lambdaQuery() + .eq(ProcessNodeRecord::getProcessInstanceId, processInstanceId) + .eq(ProcessNodeRecord::getStatus, NodeStatusEnum.YJS.getCode()) + .list(); + Set collect = processNodeRecordList.stream() + .map(ProcessNodeRecord::getNodeId) + .collect(Collectors.toSet()); + completeNodeSet.addAll(collect); + } + + Process oaForms = processService.getByFlowId(flowId); + String process = oaForms.getProcess(); + Node nodeDto = JSON.parseObject(process, Node.class); + + List processNodeShowDtos = NodeFormatUtil.formatProcessNodeShow(nodeDto, completeNodeSet, + new HashSet<>(), processInstanceId, paramMap); + + return R.ok(processNodeShowDtos); + } + + /** + * 流程详情 + * @param processInstanceId + * @return + */ + @Override + public R detail(String processInstanceId) { + ProcessInstanceRecord processInstanceRecord = processInstanceRecordService.lambdaQuery() + .eq(ProcessInstanceRecord::getProcessInstanceId, processInstanceId) + .one(); + + Process oaForms = processService.getByFlowId(processInstanceRecord.getFlowId()); + if (oaForms == null) { + return R.failed("流程不存在"); + } + + // 发起人变量数据 + String formData = processInstanceRecord.getFormData(); + Map variableMap = JSON.parseObject(formData, new TypeReference<>() { + }); + // 发起人表单权限 + String process = oaForms.getProcess(); + Node nodeDto = JSON.parseObject(process, Node.class); + Map formPerms1 = nodeDto.getFormPerms(); + + List jsonObjectList = JSON.parseArray(oaForms.getFormItems(), FormItemVO.class); + for (FormItemVO formItemVO : jsonObjectList) { + String id = formItemVO.getId(); + String perm = formPerms1.get(id); + + formItemVO.setPerm(StrUtil.isBlankIfStr(perm) ? ProcessInstanceConstant.FormPermClass.READ + : (StrUtil.equals(perm, ProcessInstanceConstant.FormPermClass.HIDE) ? perm + : ProcessInstanceConstant.FormPermClass.READ)); + + if (formItemVO.getType().equals(FormTypeEnum.LAYOUT.getType())) { + // 明细 + List> subParamList = MapUtil.get(variableMap, id, + new cn.hutool.core.lang.TypeReference<>() { + }); + + Object value = formItemVO.getProps().getValue(); + + List> l = new ArrayList<>(); + for (Map map : subParamList) { + List subItemList = Convert.toList(FormItemVO.class, value); + for (FormItemVO itemVO : subItemList) { + itemVO.getProps().setValue(map.get(itemVO.getId())); + + String permSub = formPerms1.get(itemVO.getId()); + + itemVO.setPerm(StrUtil.isBlankIfStr(permSub) ? ProcessInstanceConstant.FormPermClass.READ + : (StrUtil.equals(permSub, ProcessInstanceConstant.FormPermClass.HIDE) ? permSub + : ProcessInstanceConstant.FormPermClass.READ)); + + } + l.add(subItemList); + } + formItemVO.getProps().setValue(l); + + } + else { + formItemVO.getProps().setValue(variableMap.get(id)); + + } + + } + Dict set = Dict.create() + .set("processInstanceId", processInstanceId) + .set("process", oaForms.getProcess()) + + .set("formItems", jsonObjectList); + + return R.ok(set); + } + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/ProcessNodeDataServiceImpl.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/ProcessNodeDataServiceImpl.java new file mode 100644 index 000000000..8691e7b0b --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/ProcessNodeDataServiceImpl.java @@ -0,0 +1,60 @@ +package com.pig4cloud.pigx.flow.task.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.task.dto.Node; +import com.pig4cloud.pigx.flow.task.dto.ProcessNodeDataDto; +import com.pig4cloud.pigx.flow.task.entity.ProcessNodeData; +import com.pig4cloud.pigx.flow.task.mapper.ProcessNodeDataMapper; +import com.pig4cloud.pigx.flow.task.service.IProcessNodeDataService; +import org.springframework.stereotype.Service; + +import java.util.Optional; + +/** + *

+ * 流程节点数据 服务实现类 + *

+ * + * @author Vincent + * @since 2023-05-07 + */ +@Service +public class ProcessNodeDataServiceImpl extends ServiceImpl + implements IProcessNodeDataService { + + /** + * 保存流程节点数据。 + * @param processNodeDataDto 流程节点数据DTO + * @return 保存结果 + */ + @Override + public R saveNodeData(ProcessNodeDataDto processNodeDataDto) { + ProcessNodeData processNodeData = BeanUtil.copyProperties(processNodeDataDto, ProcessNodeData.class); + this.save(processNodeData); + return R.ok(); + } + + /** + * 获取节点数据。 + * @param flowId 流程ID + * @param nodeId 节点ID + * @return 节点数据 + */ + @Override + public R getNodeData(String flowId, String nodeId) { + Optional processNodeDataOptional = this.lambdaQuery() + .eq(ProcessNodeData::getFlowId, flowId) + .eq(ProcessNodeData::getNodeId, nodeId) + .oneOpt(); + + Node node = processNodeDataOptional + .map(processNodeData -> JSONUtil.toBean(processNodeData.getData(), Node.class)) + .orElse(null); + + return R.ok(node); + } + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/ProcessNodeRecordAssignUserServiceImpl.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/ProcessNodeRecordAssignUserServiceImpl.java new file mode 100644 index 000000000..3356dfd7b --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/ProcessNodeRecordAssignUserServiceImpl.java @@ -0,0 +1,89 @@ +package com.pig4cloud.pigx.flow.task.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.task.constant.NodeStatusEnum; +import com.pig4cloud.pigx.flow.task.dto.ProcessNodeRecordAssignUserParamDto; +import com.pig4cloud.pigx.flow.task.entity.ProcessNodeRecordAssignUser; +import com.pig4cloud.pigx.flow.task.mapper.ProcessNodeRecordAssignUserMapper; +import com.pig4cloud.pigx.flow.task.service.IProcessNodeRecordAssignUserService; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; + +/** + *

+ * 流程节点记录-执行人 服务实现类 + *

+ * + * @author cxygzl + * @since 2023-05-10 + */ +@Service +public class ProcessNodeRecordAssignUserServiceImpl + extends ServiceImpl + implements IProcessNodeRecordAssignUserService { + + /** + * 设置执行人 + * @param processNodeRecordAssignUserParamDto + * @return + */ + @Override + public R addAssignUser(ProcessNodeRecordAssignUserParamDto processNodeRecordAssignUserParamDto) { + if (StrUtil.isNotBlank(processNodeRecordAssignUserParamDto.getApproveDesc())) { + ProcessNodeRecordAssignUser processNodeRecordAssignUser = this.lambdaQuery() + .eq(ProcessNodeRecordAssignUser::getTaskId, processNodeRecordAssignUserParamDto.getTaskId()) + .orderByDesc(ProcessNodeRecordAssignUser::getId) + .last("limit 1") + .one(); + if (processNodeRecordAssignUser != null) { + processNodeRecordAssignUser.setApproveDesc(processNodeRecordAssignUserParamDto.getApproveDesc()); + processNodeRecordAssignUser.setTaskType(processNodeRecordAssignUserParamDto.getTaskType()); + processNodeRecordAssignUser.setStatus(NodeStatusEnum.YJS.getCode()); + processNodeRecordAssignUser.setEndTime(LocalDateTime.now()); + this.updateById(processNodeRecordAssignUser); + } + + } + + ProcessNodeRecordAssignUser processNodeRecordAssignUser = BeanUtil + .copyProperties(processNodeRecordAssignUserParamDto, ProcessNodeRecordAssignUser.class); + processNodeRecordAssignUser.setStartTime(LocalDateTime.now()); + processNodeRecordAssignUser.setStatus(NodeStatusEnum.JXZ.getCode()); + processNodeRecordAssignUser.setApproveDesc(""); + processNodeRecordAssignUser.setTaskType(""); + this.save(processNodeRecordAssignUser); + + return R.ok(); + } + + /** + * 任务完成通知 + * @param processNodeRecordAssignUserParamDto + * @return + */ + @Override + public R completeTaskEvent(ProcessNodeRecordAssignUserParamDto processNodeRecordAssignUserParamDto) { + ProcessNodeRecordAssignUser processNodeRecordAssignUser = this.lambdaQuery() + .eq(ProcessNodeRecordAssignUser::getTaskId, processNodeRecordAssignUserParamDto.getTaskId()) + .eq(ProcessNodeRecordAssignUser::getUserId, processNodeRecordAssignUserParamDto.getUserId()) + .eq(ProcessNodeRecordAssignUser::getProcessInstanceId, + processNodeRecordAssignUserParamDto.getProcessInstanceId()) + .eq(ProcessNodeRecordAssignUser::getStatus, NodeStatusEnum.JXZ.getCode()) + .orderByDesc(ProcessNodeRecordAssignUser::getId) + .last("limit 1") + .one(); + processNodeRecordAssignUser.setStatus(NodeStatusEnum.YJS.getCode()); + processNodeRecordAssignUser.setApproveDesc(processNodeRecordAssignUserParamDto.getApproveDesc()); + processNodeRecordAssignUser.setEndTime(LocalDateTime.now()); + processNodeRecordAssignUser.setData(processNodeRecordAssignUserParamDto.getData()); + processNodeRecordAssignUser.setLocalData(processNodeRecordAssignUserParamDto.getLocalData()); + processNodeRecordAssignUser.setTaskType("COMPLETE"); + this.updateById(processNodeRecordAssignUser); + return R.ok(); + } + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/ProcessNodeRecordServiceImpl.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/ProcessNodeRecordServiceImpl.java new file mode 100644 index 000000000..703c5d721 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/ProcessNodeRecordServiceImpl.java @@ -0,0 +1,67 @@ +package com.pig4cloud.pigx.flow.task.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import com.alibaba.fastjson2.JSON; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.task.constant.NodeStatusEnum; +import com.pig4cloud.pigx.flow.task.dto.ProcessNodeRecordParamDto; +import com.pig4cloud.pigx.flow.task.entity.ProcessNodeRecord; +import com.pig4cloud.pigx.flow.task.mapper.ProcessNodeRecordMapper; +import com.pig4cloud.pigx.flow.task.service.IProcessNodeRecordService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.Date; + +/** + *

+ * 流程节点记录 服务实现类 + *

+ * + * @author cxygzl + * @since 2023-05-10 + */ +@Slf4j +@Service +public class ProcessNodeRecordServiceImpl extends ServiceImpl + implements IProcessNodeRecordService { + + /** + * 节点开始 + * @param processNodeRecordParamDto + * @return + */ + @Override + public R start(ProcessNodeRecordParamDto processNodeRecordParamDto) { + + ProcessNodeRecord processNodeRecord = BeanUtil.copyProperties(processNodeRecordParamDto, + ProcessNodeRecord.class); + processNodeRecord.setStartTime(new Date()); + processNodeRecord.setStatus(NodeStatusEnum.JXZ.getCode()); + + this.save(processNodeRecord); + return R.ok(); + } + + /** + * 节点结束 + * @param processNodeRecordParamDto + * @return + */ + @Override + public R complete(ProcessNodeRecordParamDto processNodeRecordParamDto) { + + log.info("节点结束---{}", JSON.toJSONString(processNodeRecordParamDto)); + + // TODO 完成节点和完成任务要区分下 + this.lambdaUpdate() + .set(ProcessNodeRecord::getStatus, NodeStatusEnum.YJS.getCode()) + .set(ProcessNodeRecord::getEndTime, new Date()) + .eq(ProcessNodeRecord::getProcessInstanceId, processNodeRecordParamDto.getProcessInstanceId()) + .eq(ProcessNodeRecord::getNodeId, processNodeRecordParamDto.getNodeId()) + .update(new ProcessNodeRecord()); + return R.ok(); + } + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/ProcessServiceImpl.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/ProcessServiceImpl.java new file mode 100644 index 000000000..c8fbb8749 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/ProcessServiceImpl.java @@ -0,0 +1,252 @@ +package com.pig4cloud.pigx.flow.task.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import com.alibaba.fastjson2.JSON; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.common.security.util.SecurityUtils; +import com.pig4cloud.pigx.common.sequence.sequence.Sequence; +import com.pig4cloud.pigx.flow.task.api.feign.RemoteFlowEngineService; +import com.pig4cloud.pigx.flow.task.constant.FormTypeEnum; +import com.pig4cloud.pigx.flow.task.constant.ProcessInstanceConstant; +import com.pig4cloud.pigx.flow.task.dto.Node; +import com.pig4cloud.pigx.flow.task.dto.NodeUser; +import com.pig4cloud.pigx.flow.task.entity.Process; +import com.pig4cloud.pigx.flow.task.entity.ProcessStarter; +import com.pig4cloud.pigx.flow.task.mapper.ProcessMapper; +import com.pig4cloud.pigx.flow.task.service.IProcessService; +import com.pig4cloud.pigx.flow.task.service.IProcessStarterService; +import com.pig4cloud.pigx.flow.task.utils.NodeUtil; +import com.pig4cloud.pigx.flow.task.vo.FormItemVO; +import com.pig4cloud.pigx.flow.task.vo.ProcessVO; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + *

+ * 服务实现类 + *

+ * + * @author cxygzl + * @since 2023-05-25 + */ +@Service +@RequiredArgsConstructor +public class ProcessServiceImpl extends ServiceImpl implements IProcessService { + + private final IProcessStarterService processStarterService; + + private final RemoteFlowEngineService flowEngineService; + + private final Sequence flowSequence; + + /** + * 获取详细数据 + * @param flowId + * @return + */ + @Override + public R getDetail(String flowId) { + // 获取流程详情 + ProcessVO processVO = this.getProcessVO(flowId); + return R.ok(processVO); + } + + /** + * 根据流程ID获取流程详情 + * @param flowId 流程ID + * @return 流程详情 + */ + private ProcessVO getProcessVO(String flowId) { + + Process oaForms = getByFlowId(flowId); + String process = oaForms.getProcess(); + String formItems = oaForms.getFormItems(); + Node startNode = JSON.parseObject(process, Node.class); + + Map formPerms = startNode.getFormPerms(); + List formItemVOList = JSON.parseArray(formItems, FormItemVO.class); + for (FormItemVO formItemVO : formItemVOList) { + String perm = MapUtil.getStr(formPerms, formItemVO.getId(), ProcessInstanceConstant.FormPermClass.EDIT); + formItemVO.setPerm(perm); + + // 发号器赋值 + if (StrUtil.equals(formItemVO.getType(), FormTypeEnum.SEQUENCE.getType())) { + FormItemVO.Props props = formItemVO.getProps(); + String prefix = props.getPrefix(); + String nextNo = flowSequence.nextNo(); + formItemVO.setPlaceholder(StrUtil.isNotBlank(prefix) ? prefix + nextNo : nextNo); + props.setValue(StrUtil.isNotBlank(prefix) ? prefix + nextNo : nextNo); + formItemVO.setProps(props); + } + + if (StrUtil.equals(formItemVO.getType(), FormTypeEnum.LAYOUT.getType())) { + // 明细 + Object value = formItemVO.getProps().getValue(); + List subList = Convert.toList(FormItemVO.class, value); + for (FormItemVO itemVO : subList) { + String perm1 = MapUtil.getStr(formPerms, itemVO.getId(), + ProcessInstanceConstant.FormPermClass.EDIT); + itemVO.setPerm(perm1); + } + + formItemVO.getProps().setValue(subList); + formItemVO.getProps(); + } + + } + oaForms.setFormItems(JSON.toJSONString(formItemVOList)); + + List selectUserNodeId = NodeUtil.selectUserNodeId(startNode); + + ProcessVO processVO = BeanUtil.copyProperties(oaForms, ProcessVO.class); + processVO.setSelectUserNodeId(selectUserNodeId); + + return processVO; + } + + /** + * 根据流程ID获取流程 + * @param flowId 流程ID + * @return 流程 + */ + @Override + public Process getByFlowId(String flowId) { + return this.lambdaQuery().eq(Process::getFlowId, flowId).one(); + } + + /** + * 更新流程 + * @param process 流程 + */ + @Override + public void updateByFlowId(Process process) { + this.lambdaUpdate().eq(Process::getFlowId, process.getFlowId()).update(process); + } + + /** + * 隐藏流程 + * @param flowId 流程ID + */ + @Override + public void hide(String flowId) { + this.lambdaUpdate().set(Process::getHidden, true).eq(Process::getFlowId, flowId).update(new Process()); + } + + /** + * 创建流程 + * @param process 流程 + * @return 操作结果 + */ + @Override + public R create(Process process) { + Map map = new HashMap<>(); + map.put("process", process); + map.put("userId", SecurityUtils.getUser().getId()); + R r = flowEngineService.createFlow(map); + if (!r.isOk()) { + return R.failed(r.getMsg()); + } + String flowId = r.getData(); + + NodeUser nodeUser = JSONUtil.toList(process.getAdmin(), NodeUser.class).get(0); + + if (StrUtil.isNotBlank(process.getFlowId())) { + + Process oldProcess = this.getByFlowId(process.getFlowId()); + this.hide(process.getFlowId()); + // 修改所有的管理员 + this.lambdaUpdate() + .set(Process::getAdminId, nodeUser.getId()) + .eq(Process::getUniqueId, oldProcess.getUniqueId()) + .update(new Process()); + + } + + Node startNode = JSONUtil.toBean(process.getProcess(), Node.class); + + List nodeUserList = startNode.getNodeUserList(); + + StringBuilder stringBuilder = new StringBuilder(); + if (CollUtil.isNotEmpty(nodeUserList)) { + int index = 0; + + for (NodeUser user : nodeUserList) { + if (index > 0) { + stringBuilder.append(","); + } + stringBuilder.append(user.getName()); + index++; + if (index > 5) { + break; + } + + } + } + + Process p = new Process(); + p.setFlowId(flowId); + p.setName(process.getName()); + p.setLogo(process.getLogo()); + p.setSettings(process.getSettings()); + p.setGroupId(process.getGroupId()); + p.setFormItems(process.getFormItems()); + p.setProcess(process.getProcess()); + p.setRemark(process.getRemark()); + p.setSort(0); + p.setHidden(false); + p.setStop(false); + p.setAdminId(nodeUser.getId()); + p.setUniqueId(IdUtil.fastSimpleUUID()); + p.setAdmin(process.getAdmin()); + p.setRangeShow(stringBuilder.toString()); + + this.save(p); + + // 保存范围 + + for (NodeUser nodeUserDto : nodeUserList) { + ProcessStarter processStarter = new ProcessStarter(); + + processStarter.setProcessId(p.getId()); + processStarter.setTypeId(nodeUserDto.getId()); + processStarter.setType(nodeUserDto.getType()); + processStarterService.save(processStarter); + + } + + return R.ok(); + } + + /** + * 编辑表单 + * @param flowId 流程ID + * @param type 类型 stop using delete + * @param groupId 分组ID + * @return 操作结果 + */ + @Override + public R update(String flowId, String type, Long groupId) { + Process process = new Process(); + process.setFlowId(flowId); + process.setStop("stop".equals(type)); + process.setHidden("delete".equals(type)); + process.setGroupId(groupId); + + this.updateByFlowId(process); + + return R.ok(); + } + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/ProcessStarterServiceImpl.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/ProcessStarterServiceImpl.java new file mode 100644 index 000000000..5e4f74efe --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/ProcessStarterServiceImpl.java @@ -0,0 +1,21 @@ +package com.pig4cloud.pigx.flow.task.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.pig4cloud.pigx.flow.task.entity.ProcessStarter; +import com.pig4cloud.pigx.flow.task.mapper.ProcessStarterMapper; +import com.pig4cloud.pigx.flow.task.service.IProcessStarterService; +import org.springframework.stereotype.Service; + +/** + *

+ * 流程发起人 服务实现类 + *

+ * + * @author Vincent + * @since 2023-05-30 + */ +@Service +public class ProcessStarterServiceImpl extends ServiceImpl + implements IProcessStarterService { + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/RemoteServiceImpl.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/RemoteServiceImpl.java new file mode 100644 index 000000000..3e71b308b --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/RemoteServiceImpl.java @@ -0,0 +1,262 @@ +package com.pig4cloud.pigx.flow.task.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.thread.ThreadUtil; +import cn.hutool.core.util.ArrayUtil; +import com.pig4cloud.pigx.admin.api.entity.SysDept; +import com.pig4cloud.pigx.admin.api.entity.SysUser; +import com.pig4cloud.pigx.admin.api.feign.RemoteDeptService; +import com.pig4cloud.pigx.admin.api.feign.RemoteUserService; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.flow.task.constant.NodeStatusEnum; +import com.pig4cloud.pigx.flow.task.dto.*; +import com.pig4cloud.pigx.flow.task.entity.Process; +import com.pig4cloud.pigx.flow.task.entity.ProcessCopy; +import com.pig4cloud.pigx.flow.task.entity.ProcessGroup; +import com.pig4cloud.pigx.flow.task.entity.ProcessInstanceRecord; +import com.pig4cloud.pigx.flow.task.service.*; +import com.pig4cloud.pigx.flow.task.utils.DataUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +@Service +@Slf4j +@RequiredArgsConstructor +public class RemoteServiceImpl implements IRemoteService { + + private final IProcessInstanceRecordService processInstanceRecordService; + + private final IProcessNodeRecordService processNodeRecordService; + + private final IProcessNodeRecordAssignUserService processNodeRecordAssignUserService; + + private final IProcessInstanceService processInstanceService; + + private final IProcessCopyService processCopyService; + + private final IProcessService processService; + + private final IProcessGroupService processGroupService; + + private final RemoteUserService userService; + + private final RemoteDeptService deptService; + + /** + * 根据角色id集合查询用户id集合 + * @param roleIdList + * @return + */ + @Override + public R> queryUserIdListByRoleIdList(List roleIdList) { + return userService.getUserIdListByRoleIdList(roleIdList); + } + + /** + * 保存抄送 + * @param copyDto + * @return + */ + @Override + public R saveCC(ProcessCopyDto copyDto) { + + String processInstanceId = copyDto.getProcessInstanceId(); + + // 如果抄送是第一个节点 会出现查询不到的情况 + ThreadUtil.execute(() -> { + try { + ProcessInstanceRecord processInstanceRecord = processInstanceRecordService.lambdaQuery() + .eq(ProcessInstanceRecord::getProcessInstanceId, processInstanceId) + .one(); + + int index = 10; + while (index > 0 && processInstanceRecord == null) { + TimeUnit.SECONDS.sleep(5); + processInstanceRecord = processInstanceRecordService.lambdaQuery() + .eq(ProcessInstanceRecord::getProcessInstanceId, processInstanceId) + .one(); + index--; + } + + ProcessCopy processCopy = BeanUtil.copyProperties(copyDto, ProcessCopy.class); + processCopy.setGroupId(processInstanceRecord.getGroupId()); + processCopy.setGroupName(processInstanceRecord.getGroupName()); + processCopy.setProcessName(processInstanceRecord.getName()); + processCopy.setStartTime(processInstanceRecord.getCreateTime()); + + processCopyService.save(processCopy); + } + catch (Exception e) { + log.error("Error:", e); + } + }); + + return R.ok(); + } + + /** + * 检查是否是所有的父级 + * @param checkParentDto + * @return + */ + @Override + public R checkIsAllParent(CheckParentDto checkParentDto) { + + Long parentId = checkParentDto.getParentId(); + List deptIdList = checkParentDto.getDeptIdList(); + // 查询子级包括自己 + List allDept = deptService.getAllDept().getData(); + List childrenDeptList = DataUtil.selectChildrenByDept(parentId, allDept); + + List childrenDeptIdList = childrenDeptList.stream().map(SysDept::getDeptId).collect(Collectors.toList()); + childrenDeptIdList.remove(parentId); + + List remainIdList = CollUtil.removeAny(deptIdList, ArrayUtil.toArray(childrenDeptIdList, Long.class)); + + return R.ok(remainIdList.isEmpty()); + } + + /** + * 根据部门id集合查询用户id集合 + * @param depIdList + * @return + */ + @Override + public R> queryUserIdListByDepIdList(List depIdList) { + List list = userService.getUserIdListByDeptIdList(depIdList) + .getData() + .stream() + .map(SysUser::getUserId) + .toList(); + return R.ok(list); + } + + /** + * 检查是否是所有的子级 + * @param checkChildDto + * @return + */ + @Override + public R checkIsAllChild(CheckChildDto checkChildDto) { + Long childId = checkChildDto.getChildId(); + List deptIdList = checkChildDto.getDeptIdList(); + // 查询父级包括自己 + List allDept = deptService.getAllDept().getData(); + List parentDeptList = DataUtil.selectParentByDept(childId, allDept); + + List parentDeptIdList = parentDeptList.stream().map(SysDept::getDeptId).collect(Collectors.toList()); + parentDeptIdList.remove(childId); + + List remainIdList = CollUtil.removeAny(deptIdList, ArrayUtil.toArray(parentDeptIdList, Long.class)); + + return R.ok(remainIdList.isEmpty()); + } + + /** + * 获取用户的信息-包括扩展字段 + * @param userId + * @return + */ + @Override + public R> queryUserAllInfo(long userId) { + SysUser sysUser = userService.getUserById(userId).getData(); + return R.ok(BeanUtil.beanToMap(sysUser)); + } + + /** + * 开始节点事件 + * @param recordParamDto + * @return + */ + @Override + public R startNodeEvent(ProcessNodeRecordParamDto recordParamDto) { + return processNodeRecordService.start(recordParamDto); + } + + /** + * 流程创建了 + * @param processInstanceRecordParamDto + * @return + */ + @Override + public R createProcessEvent(ProcessInstanceRecordParamDto processInstanceRecordParamDto) { + ProcessInstanceRecord entity = BeanUtil.copyProperties(processInstanceRecordParamDto, + ProcessInstanceRecord.class); + + Process oaForms = processService.getByFlowId(processInstanceRecordParamDto.getFlowId()); + + ProcessGroup oaFormGroups = processGroupService.getById(oaForms.getGroupId()); + + entity.setName(oaForms.getName()); + entity.setLogo(oaForms.getLogo()); + entity.setUserId(processInstanceRecordParamDto.getUserId()); + entity.setFlowId(processInstanceRecordParamDto.getFlowId()); + entity.setProcessInstanceId(processInstanceRecordParamDto.getProcessInstanceId()); + entity.setGroupId(oaFormGroups.getId()); + entity.setGroupName(oaFormGroups.getGroupName()); + entity.setStatus(NodeStatusEnum.JXZ.getCode()); + + processInstanceRecordService.save(entity); + + return R.ok(); + } + + /** + * 完成节点事件 + * @param recordParamDto + * @return + */ + @Override + public R endNodeEvent(ProcessNodeRecordParamDto recordParamDto) { + return processNodeRecordService.complete(recordParamDto); + } + + /** + * 开始设置执行人 + * @param processNodeRecordAssignUserParamDto + * @return + */ + @Override + public R startAssignUser(ProcessNodeRecordAssignUserParamDto processNodeRecordAssignUserParamDto) { + return processNodeRecordAssignUserService.addAssignUser(processNodeRecordAssignUserParamDto); + } + + /** + * 任务结束事件 + * @param processNodeRecordAssignUserParamDto + * @return + */ + @Override + public R taskEndEvent(ProcessNodeRecordAssignUserParamDto processNodeRecordAssignUserParamDto) { + return processNodeRecordAssignUserService.completeTaskEvent(processNodeRecordAssignUserParamDto); + } + + /** + * 实例结束 + * @param processInstanceId + * @return + */ + @Override + public R endProcess(String processInstanceId) { + return processInstanceService.end(processInstanceId); + } + + /** + * 查询流程管理员 + * @param flowId + * @return + */ + @Override + public R queryProcessAdmin(String flowId) { + Process process = processService.getByFlowId(flowId); + return R.ok(process.getAdminId()); + } + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/TaskServiceImpl.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/TaskServiceImpl.java new file mode 100644 index 000000000..bf977ffe5 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/service/impl/TaskServiceImpl.java @@ -0,0 +1,314 @@ +package com.pig4cloud.pigx.flow.task.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.Dict; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.TypeReference; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.common.security.util.SecurityUtils; +import com.pig4cloud.pigx.flow.task.api.feign.RemoteFlowEngineService; +import com.pig4cloud.pigx.flow.task.constant.FormTypeEnum; +import com.pig4cloud.pigx.flow.task.constant.NodeStatusEnum; +import com.pig4cloud.pigx.flow.task.constant.ProcessInstanceConstant; +import com.pig4cloud.pigx.flow.task.dto.Node; +import com.pig4cloud.pigx.flow.task.dto.TaskParamDto; +import com.pig4cloud.pigx.flow.task.dto.TaskResultDto; +import com.pig4cloud.pigx.flow.task.entity.Process; +import com.pig4cloud.pigx.flow.task.entity.ProcessInstanceRecord; +import com.pig4cloud.pigx.flow.task.entity.ProcessNodeRecordAssignUser; +import com.pig4cloud.pigx.flow.task.service.*; +import com.pig4cloud.pigx.flow.task.vo.FormItemVO; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +@Slf4j +@RequiredArgsConstructor +public class TaskServiceImpl implements ITaskService { + + private final RemoteFlowEngineService flowEngineService; + + private final IProcessService processService; + + private final IProcessNodeDataService nodeDataService; + + private final IProcessNodeRecordAssignUserService processNodeRecordAssignUserService; + + private final IProcessInstanceRecordService processInstanceRecordService; + + /** + * 查询任务 + * @param taskId + * @param view + * @return + */ + @Override + public R queryTask(String taskId, boolean view) { + + long userId = SecurityUtils.getUser().getId(); + + R r = flowEngineService.queryTask(taskId, userId); + + if (!r.isOk()) { + return R.failed(r.getMsg()); + } + + TaskResultDto taskResultDto = r.getData(); + + // 变量 + Map paramMap = taskResultDto.getVariableAll(); + // 是否是当前活动任务 + Boolean currentTask = taskResultDto.getCurrentTask(); + if (!currentTask) { + ProcessNodeRecordAssignUser processNodeRecordAssignUser = processNodeRecordAssignUserService.lambdaQuery() + .eq(ProcessNodeRecordAssignUser::getTaskId, taskId) + .eq(ProcessNodeRecordAssignUser::getUserId, userId) + .eq(ProcessNodeRecordAssignUser::getStatus, NodeStatusEnum.YJS.getCode()) + .last("limit 1") + .orderByDesc(ProcessNodeRecordAssignUser::getEndTime) + .one(); + + if (processNodeRecordAssignUser != null) { + String data = processNodeRecordAssignUser.getData(); + if (StrUtil.isNotBlank(data)) { + Map collect = JSON.parseObject(data, new TypeReference>() { + }); + paramMap.putAll(collect); + + } + } + + } + + // 当前节点数据 + Node node = nodeDataService.getNodeData(taskResultDto.getFlowId(), taskResultDto.getNodeId()).getData(); + Map formPerms = node.getFormPerms(); + + Process oaForms = processService.getByFlowId(taskResultDto.getFlowId()); + if (oaForms == null) { + return R.failed("流程不存在"); + } + + List formItemVOList = JSONUtil.toList(oaForms.getFormItems(), FormItemVO.class); + for (FormItemVO formItemVO : formItemVOList) { + + String id = formItemVO.getId(); + + String perm = formPerms.get(id); + + if (StrUtil.isNotBlank(perm)) { + + formItemVO.setPerm(view ? (ProcessInstanceConstant.FormPermClass.EDIT.equals(perm) + ? ProcessInstanceConstant.FormPermClass.READ : perm) : perm); + + } + else { + formItemVO.setPerm(ProcessInstanceConstant.FormPermClass.HIDE); + } + + if (formItemVO.getType().equals(FormTypeEnum.LAYOUT.getType())) { + // 明细 + + List> subParamList = MapUtil.get(paramMap, id, + new cn.hutool.core.lang.TypeReference>>() { + }); + + Object value = formItemVO.getProps().getValue(); + + List> l = new ArrayList<>(); + for (Map map : subParamList) { + List subItemList = Convert.toList(FormItemVO.class, value); + for (FormItemVO itemVO : subItemList) { + itemVO.getProps().setValue(map.get(itemVO.getId())); + + String permSub = formPerms.get(itemVO.getId()); + if (StrUtil.isNotBlank(permSub)) { + itemVO.setPerm(view ? (ProcessInstanceConstant.FormPermClass.EDIT.equals(permSub) + ? ProcessInstanceConstant.FormPermClass.READ : permSub) : permSub); + + } + else { + itemVO.setPerm(ProcessInstanceConstant.FormPermClass.HIDE); + } + + } + l.add(subItemList); + } + formItemVO.getProps().setValue(l); + { + List subItemList = Convert.toList(FormItemVO.class, value); + for (FormItemVO itemVO : subItemList) { + + String permSub = formPerms.get(itemVO.getId()); + if (StrUtil.isNotBlank(permSub)) { + + itemVO.setPerm(permSub); + + } + else { + itemVO.setPerm(ProcessInstanceConstant.FormPermClass.HIDE); + } + + } + formItemVO.getProps().setOriForm(subItemList); + + } + + } + else { + formItemVO.getProps().setValue(paramMap.get(id)); + + } + + } + Dict set = Dict.create() + .set("processInstanceId", taskResultDto.getProcessInstanceId()) + .set("node", taskResultDto.getTaskNode()) + .set("process", oaForms.getProcess()) + .set("delegateAgain", taskResultDto.getDelegate()) + .set("delegationTask", StrUtil.equals(taskResultDto.getDelegationState(), "PENDING")) + + .set("formItems", formItemVOList); + + return R.ok(set); + } + + /** + * 完成任务 + * @param taskParamDto + * @return + */ + @Override + public R completeTask(TaskParamDto taskParamDto) { + long userId = SecurityUtils.getUser().getId(); + taskParamDto.setUserId(String.valueOf(userId)); + + R r = flowEngineService.completeTask(taskParamDto); + + if (!r.isOk()) { + return R.failed(r.getMsg()); + } + + return R.ok(); + } + + /** + * 前加签 + * @param taskParamDto + * @return + */ + @Transactional + @Override + public R delegateTask(TaskParamDto taskParamDto) { + + taskParamDto.setUserId(SecurityUtils.getUser().getId().toString()); + + R r = flowEngineService.delegateTask(taskParamDto); + if (!r.isOk()) { + return R.failed(r.getMsg()); + } + + return R.ok(); + } + + /** + * 加签完成任务 + * @param taskParamDto + * @return + */ + @Override + public R resolveTask(TaskParamDto taskParamDto) { + R r = flowEngineService.resolveTask(taskParamDto); + if (!r.isOk()) { + return R.failed(r.getMsg()); + } + + return R.ok(); + } + + /** + * 设置执行人 + * @param taskParamDto + * @return + */ + @Override + public R setAssignee(TaskParamDto taskParamDto) { + taskParamDto.setUserId(SecurityUtils.getUser().getId().toString()); + R r = flowEngineService.setAssignee(taskParamDto); + if (!r.isOk()) { + return R.failed(r.getMsg()); + } + + return R.ok(); + } + + /** + * 结束流程 + * @param taskParamDto + * @return + */ + @Override + public R stopProcessInstance(TaskParamDto taskParamDto) { + + String processInstanceId = taskParamDto.getProcessInstanceId(); + + List allStopProcessInstanceIdList = getAllStopProcessInstanceIdList(processInstanceId); + CollUtil.reverse(allStopProcessInstanceIdList); + allStopProcessInstanceIdList.add(processInstanceId); + + taskParamDto.setProcessInstanceIdList(allStopProcessInstanceIdList); + taskParamDto.setUserId(SecurityUtils.getUser().getId().toString()); + R r = flowEngineService.stopProcessInstance(taskParamDto); + + if (!r.isOk()) { + return R.failed(r.getMsg()); + } + + return R.ok(); + } + + /** + * 退回 + * @param taskParamDto + * @return + */ + @Override + public R back(TaskParamDto taskParamDto) { + taskParamDto.setUserId(SecurityUtils.getUser().getId().toString()); + R r = flowEngineService.back(taskParamDto); + if (!r.isOk()) { + return R.failed(r.getMsg()); + } + + return R.ok(); + } + + private List getAllStopProcessInstanceIdList(String processInstanceId) { + List list = processInstanceRecordService.lambdaQuery() + .eq(ProcessInstanceRecord::getParentProcessInstanceId, processInstanceId) + .list(); + + List collect = list.stream().map(w -> w.getProcessInstanceId()).collect(Collectors.toList()); + + for (ProcessInstanceRecord processInstanceRecord : list) { + List allStopProcessInstanceIdList = getAllStopProcessInstanceIdList( + processInstanceRecord.getProcessInstanceId()); + + collect.addAll(allStopProcessInstanceIdList); + + } + return collect; + } + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/utils/DataUtil.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/utils/DataUtil.java new file mode 100644 index 000000000..57d3adaed --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/utils/DataUtil.java @@ -0,0 +1,81 @@ +package com.pig4cloud.pigx.flow.task.utils; + +import cn.hutool.core.collection.CollUtil; +import com.pig4cloud.pigx.admin.api.entity.SysDept; +import com.pig4cloud.pigx.admin.api.entity.SysMenu; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class DataUtil { + + /** + * 根据当前部门id,向上查找所有的部门 + * @param deptId + * @param allDeptList + * @return 返回包括自己部门在内的所有父级部门 + */ + public static List selectParentByDept(long deptId, List allDeptList) { + List list = new ArrayList<>(); + SysDept dept = allDeptList.stream().filter(w -> w.getDeptId() == deptId).findAny().orElse(null); + if (dept == null || dept.getParentId() == null) { + return list; + } + Long parentId = dept.getParentId(); + List depts = selectParentByDept(parentId, allDeptList); + list.add(dept); + list.addAll(depts); + return list; + + } + + /** + * 根据当前部门id,向下查找所有的部门 + * @param deptId + * @param allDeptList + * @return 返回包括自己部门在内的所有子级部门 + */ + public static List selectChildrenByDept(long deptId, List allDeptList) { + List list = new ArrayList<>(); + list.add(allDeptList.stream().filter(w -> w.getDeptId() == deptId).findFirst().get()); + + List collect = allDeptList.stream() + .filter(w -> w.getParentId() == deptId) + .collect(Collectors.toList()); + if (CollUtil.isEmpty(collect)) { + return list; + } + for (SysDept dept : collect) { + List depts = selectChildrenByDept(dept.getDeptId(), allDeptList); + list.addAll(depts); + } + return list; + + } + + /** + * 根据当前菜单id,向下查找所有的菜单 + * @param menuId + * @param allMenuList + * @return 返回包括自己在内的所有子级菜单 + */ + public static List selectChildrenByMenu(long menuId, List allMenuList) { + List list = new ArrayList<>(); + list.add(allMenuList.stream().filter(w -> w.getMenuId() == menuId).findFirst().get()); + + List collect = allMenuList.stream() + .filter(w -> w.getParentId() == menuId) + .collect(Collectors.toList()); + if (CollUtil.isEmpty(collect)) { + return list; + } + for (SysMenu dept : collect) { + List depts = selectChildrenByMenu(dept.getMenuId(), allMenuList); + list.addAll(depts); + } + return list; + + } + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/utils/NodeFormatUtil.java b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/utils/NodeFormatUtil.java new file mode 100644 index 000000000..2d8dbc68f --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/java/com/pig4cloud/pigx/flow/task/utils/NodeFormatUtil.java @@ -0,0 +1,290 @@ +package com.pig4cloud.pigx.flow.task.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.spring.SpringUtil; +import com.alibaba.fastjson.JSON; +import com.pig4cloud.pigx.admin.api.entity.SysUser; +import com.pig4cloud.pigx.admin.api.feign.RemoteUserService; +import com.pig4cloud.pigx.common.security.util.SecurityUtils; +import com.pig4cloud.pigx.flow.task.constant.NodeStatusEnum; +import com.pig4cloud.pigx.flow.task.constant.NodeTypeEnum; +import com.pig4cloud.pigx.flow.task.constant.NodeUserTypeEnum; +import com.pig4cloud.pigx.flow.task.constant.ProcessInstanceConstant; +import com.pig4cloud.pigx.flow.task.dto.Node; +import com.pig4cloud.pigx.flow.task.dto.NodeUser; +import com.pig4cloud.pigx.flow.task.entity.ProcessInstanceRecord; +import com.pig4cloud.pigx.flow.task.entity.ProcessNodeRecordAssignUser; +import com.pig4cloud.pigx.flow.task.service.IProcessInstanceRecordService; +import com.pig4cloud.pigx.flow.task.service.IProcessNodeRecordAssignUserService; +import com.pig4cloud.pigx.flow.task.service.IRemoteService; +import com.pig4cloud.pigx.flow.task.vo.NodeVo; +import com.pig4cloud.pigx.flow.task.vo.UserVo; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 节点格式化显示工具 + */ +public class NodeFormatUtil { + + /** + * 格式化流程节点显示 + * @param node + * @param completeNodeSet + * @param continueNodeSet + * @param processInstanceId + * @param paramMap + */ + public static List formatProcessNodeShow(Node node, Set completeNodeSet, + Set continueNodeSet, String processInstanceId, Map paramMap) { + List list = new ArrayList<>(); + + if (!NodeUtil.isNode(node)) { + return list; + } + + String name = node.getName(); + Integer type = node.getType(); + + // SELF_SELECT + + NodeVo nodeVo = new NodeVo(); + nodeVo.setId(node.getId()); + nodeVo.setName(name); + nodeVo.setType(type); + nodeVo.setStatus(NodeStatusEnum.WKS.getCode()); + if (completeNodeSet.contains(node.getId())) { + nodeVo.setStatus(NodeStatusEnum.YJS.getCode()); + + } + if (continueNodeSet.contains(node.getId())) { + nodeVo.setStatus(NodeStatusEnum.JXZ.getCode()); + + } + + { + + nodeVo.setPlaceholder(node.getPlaceHolder()); + + } + + List userVoList = new ArrayList<>(); + if (type == NodeTypeEnum.APPROVAL.getValue().intValue()) { + + Integer assignedType = node.getAssignedType(); + + boolean selfSelect = assignedType == ProcessInstanceConstant.AssignedTypeClass.SELF_SELECT; + nodeVo.setSelectUser(selfSelect); + if (selfSelect) { + nodeVo.setMultiple(node.getMultiple()); + } + + // 用户列表 + if (StrUtil.isNotBlank(processInstanceId)) { + IProcessNodeRecordAssignUserService processNodeRecordAssignUserService = SpringUtil + .getBean(IProcessNodeRecordAssignUserService.class); + List processNodeRecordAssignUserList = processNodeRecordAssignUserService + .lambdaQuery() + .eq(ProcessNodeRecordAssignUser::getNodeId, node.getId()) + .eq(ProcessNodeRecordAssignUser::getProcessInstanceId, processInstanceId) + .orderByAsc(ProcessNodeRecordAssignUser::getCreateTime) + .list(); + Map> map = processNodeRecordAssignUserList.stream() + .collect(Collectors.groupingBy(ProcessNodeRecordAssignUser::getTaskId)); + + for (Map.Entry> entry : map.entrySet()) { + List value = entry.getValue(); + List collect = value.stream().map(w -> { + UserVo userVo = buildUser(Long.parseLong(w.getUserId())); + userVo.setShowTime(w.getEndTime()); + userVo.setApproveDesc(w.getApproveDesc()); + userVo.setStatus(w.getStatus()); + userVo.setOperType(w.getTaskType()); + return userVo; + }).toList(); + userVoList.addAll(collect); + } + + if (processNodeRecordAssignUserList.isEmpty()) { + if (assignedType == ProcessInstanceConstant.AssignedTypeClass.SELF) { + // 发起人自己 + userVoList.addAll(CollUtil.newArrayList(buildRootUser(processInstanceId))); + } + if (assignedType == ProcessInstanceConstant.AssignedTypeClass.SELF_SELECT) { + // 发起人自选 + Object variable = paramMap.get(StrUtil.format("{}_assignee_select", node.getId())); + List nodeUserDtos = JSON.parseArray(JSON.toJSONString(variable), NodeUser.class); + + List collect = nodeUserDtos.stream().map(w -> Long.valueOf(w.getId())).toList(); + for (Long aLong : collect) { + UserVo userVo = buildUser(aLong); + userVoList.addAll(CollUtil.newArrayList(userVo)); + } + } + } + + } + else if (assignedType == ProcessInstanceConstant.AssignedTypeClass.USER) { + // 指定用户 + + List nodeUserList = node.getNodeUserList(); + List tempList = buildUser(nodeUserList); + userVoList.addAll(tempList); + + } + else if (assignedType == ProcessInstanceConstant.AssignedTypeClass.FORM_USER) { + // 表单人员 + String formUser = node.getFormUserId(); + + Object o = paramMap.get(formUser); + if (o != null) { + String jsonString = JSON.toJSONString(o); + if (StrUtil.isNotBlank(jsonString)) { + List nodeUserDtoList = JSON.parseArray(jsonString, NodeUser.class); + List userIdList = nodeUserDtoList.stream().map(NodeUser::getId).toList(); + for (Long aLong : userIdList) { + userVoList.addAll(CollUtil.newArrayList(buildUser(aLong))); + } + } + } + + } + else if (assignedType == ProcessInstanceConstant.AssignedTypeClass.SELF) { + // 发起人自己 + userVoList.addAll(CollUtil.newArrayList(buildUser(SecurityUtils.getUser().getId()))); + } + + } + else if (Objects.equals(node.getType(), NodeTypeEnum.ROOT.getValue())) { + // 发起节点 + if (StrUtil.isBlank(processInstanceId)) { + UserVo userVo = buildUser(SecurityUtils.getUser().getId()); + userVoList.addAll(CollUtil.newArrayList(userVo)); + } + else { + + IProcessInstanceRecordService processInstanceRecordService = SpringUtil + .getBean(IProcessInstanceRecordService.class); + ProcessInstanceRecord processInstanceRecord = processInstanceRecordService.lambdaQuery() + .eq(ProcessInstanceRecord::getProcessInstanceId, processInstanceId) + .one(); + + UserVo userVo = buildRootUser(processInstanceId); + userVo.setShowTime(processInstanceRecord.getCreateTime()); + userVo.setStatus(NodeStatusEnum.YJS.getCode()); + userVoList.addAll(CollUtil.newArrayList(userVo)); + + } + } + else if (node.getType() == NodeTypeEnum.CC.getValue()) { + // 抄送节点 + + List nodeUserList = node.getNodeUserList(); + + List tempList = buildUser(nodeUserList); + userVoList.addAll(tempList); + + } + nodeVo.setUserVoList(userVoList); + + List branchList = new ArrayList<>(); + + if (type == NodeTypeEnum.EXCLUSIVE_GATEWAY.getValue().intValue() + || type == NodeTypeEnum.PARALLEL_GATEWAY.getValue().intValue()) { + // 条件分支 + List branchs = node.getConditionNodes(); + + for (Node branch : branchs) { + Node children = branch.getChildren(); + List processNodeShowDtos = formatProcessNodeShow(children, completeNodeSet, continueNodeSet, + processInstanceId, paramMap); + + NodeVo p = new NodeVo(); + p.setChildren(processNodeShowDtos); + + p.setPlaceholder(branch.getPlaceHolder()); + branchList.add(p); + } + } + nodeVo.setBranch(branchList); + + list.add(nodeVo); + + List next = formatProcessNodeShow(node.getChildren(), completeNodeSet, continueNodeSet, + processInstanceId, paramMap); + list.addAll(next); + + return list; + } + + /** + * 根据实例id + * @param processInstanceId + * @return + */ + private static UserVo buildRootUser(String processInstanceId) { + + IProcessInstanceRecordService processInstanceRecordService = SpringUtil + .getBean(IProcessInstanceRecordService.class); + ProcessInstanceRecord processInstanceRecord = processInstanceRecordService.lambdaQuery() + .eq(ProcessInstanceRecord::getProcessInstanceId, processInstanceId) + .one(); + Long userId = processInstanceRecord.getUserId(); + UserVo userVo = buildUser(userId); + return userVo; + } + + /** + * 根据用户id + * @param userId + * @return + */ + private static UserVo buildUser(long userId) { + RemoteUserService userService = SpringUtil.getBean(RemoteUserService.class); + SysUser user = userService.getUserById(userId).getData(); + if (user == null) { + return null; + } + + return UserVo.builder().id(userId).name(user.getName()).avatar(user.getAvatar()).build(); + } + + private static List buildUser(List nodeUserList) { + List userVoList = new ArrayList<>(); + // 用户id + List userIdList = nodeUserList.stream() + .filter(w -> StrUtil.equals(w.getType(), NodeUserTypeEnum.USER.getKey())) + .map(w -> Convert.toLong(w.getId())) + .collect(Collectors.toList()); + // 部门id + List deptIdList = nodeUserList.stream() + .filter(w -> StrUtil.equals(w.getType(), NodeUserTypeEnum.DEPT.getKey())) + .map(w -> Convert.toLong(w.getId())) + .collect(Collectors.toList()); + + if (CollUtil.isNotEmpty(deptIdList)) { + + IRemoteService iRemoteService = SpringUtil.getBean(IRemoteService.class); + + List data = iRemoteService.queryUserIdListByDepIdList(deptIdList).getData(); + + if (CollUtil.isNotEmpty(data)) { + for (long datum : data) { + if (!userIdList.contains(datum)) { + userIdList.add(datum); + } + } + } + } + { + for (Long aLong : userIdList) { + userVoList.addAll(CollUtil.newArrayList(buildUser(aLong))); + } + } + return userVoList; + } + +} diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/resources/application.yml b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/resources/application.yml new file mode 100644 index 000000000..ed6f97eca --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/resources/application.yml @@ -0,0 +1,25 @@ +server: + port: 5030 + +spring: + application: + name: @artifactId@ + cloud: + nacos: + username: @nacos.username@ + password: @nacos.password@ + discovery: + server-addr: ${NACOS_HOST:pigx-register}:${NACOS_PORT:8848} + config: + server-addr: ${spring.cloud.nacos.discovery.server-addr} + config: + import: + - optional:nacos:application-@profiles.active@.yml + - optional:nacos:${spring.application.name}-@profiles.active@.yml + datasource: + type: com.alibaba.druid.pool.DruidDataSource + druid: + driver-class-name: com.mysql.cj.jdbc.Driver + username: ${MYSQL_USER:root} + password: ${MYSQL_PWD:root} + url: jdbc:mysql://${MYSQL_HOST:pigx-mysql}:${MYSQL_PORT:3306}/${MYSQL_DB:simple_flow_biz}?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&allowMultiQueries=true diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/resources/logback-spring.xml b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/resources/logback-spring.xml new file mode 100644 index 000000000..0cd6c2983 --- /dev/null +++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/src/main/resources/logback-spring.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + ${CONSOLE_LOG_PATTERN} + + + + + + ${log.path}/debug.log + + ${log.path}/%d{yyyy-MM, aux}/debug.%d{yyyy-MM-dd}.%i.log.gz + 50MB + 30 + + + %date [%thread] %-5level [%logger{50}] %file:%line - %msg%n + + + + + + ${log.path}/error.log + + ${log.path}/%d{yyyy-MM}/error.%d{yyyy-MM-dd}.%i.log.gz + 50MB + 30 + + + %date [%thread] %-5level [%logger{50}] %file:%line - %msg%n + + + ERROR + + + + + + + + + + + + + + + + + diff --git a/pigx-flow/pigx-flow-task/pom.xml b/pigx-flow/pigx-flow-task/pom.xml new file mode 100644 index 000000000..0add965fd --- /dev/null +++ b/pigx-flow/pigx-flow-task/pom.xml @@ -0,0 +1,22 @@ + + + + 4.0.0 + + + com.pig4cloud + pigx-flow + 5.2.0-snapshot + + + pigx-flow-task + flowable 工作流业务处理模块 + pom + + + + pigx-flow-task-api + pigx-flow-task-biz + + diff --git a/pigx-flow/pom.xml b/pigx-flow/pom.xml new file mode 100644 index 000000000..83df8de50 --- /dev/null +++ b/pigx-flow/pom.xml @@ -0,0 +1,38 @@ + + + + + 4.0.0 + + com.pig4cloud + pigx + 5.2.0-snapshot + + + pigx-flow + pigx 工作流 + pom + + + pigx-flow-engine + pigx-flow-task + + diff --git a/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/config/RouterFunctionConfiguration.java b/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/config/RouterFunctionConfiguration.java index f74edccc1..a1dd724b5 100644 --- a/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/config/RouterFunctionConfiguration.java +++ b/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/config/RouterFunctionConfiguration.java @@ -44,10 +44,10 @@ public class RouterFunctionConfiguration { @Bean public RouterFunction routerFunction() { return RouterFunctions - .route(RequestPredicates.path("/code/create").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), - imageCodeCreateHandler) - .andRoute(RequestPredicates.POST("/code/check").and(RequestPredicates.accept(MediaType.ALL)), - imageCodeCheckHandler); + .route(RequestPredicates.path("/code/create").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), + imageCodeCreateHandler) + .andRoute(RequestPredicates.POST("/code/check").and(RequestPredicates.accept(MediaType.ALL)), + imageCodeCheckHandler); } diff --git a/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/filter/PigxRequestGlobalFilter.java b/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/filter/PigxRequestGlobalFilter.java index c8b74b4f6..7c52c1807 100644 --- a/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/filter/PigxRequestGlobalFilter.java +++ b/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/filter/PigxRequestGlobalFilter.java @@ -68,8 +68,9 @@ public class PigxRequestGlobalFilter implements GlobalFilter, Ordered { // 2. 重写StripPrefix addOriginalRequestUrl(exchange, request.getURI()); String rawPath = request.getURI().getRawPath(); - String newPath = "/" + Arrays.stream(StringUtils.tokenizeToStringArray(rawPath, "/")).skip(1L) - .collect(Collectors.joining("/")); + String newPath = "/" + Arrays.stream(StringUtils.tokenizeToStringArray(rawPath, "/")) + .skip(1L) + .collect(Collectors.joining("/")); ServerHttpRequest newRequest = request.mutate().path(newPath).build(); exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, newRequest.getURI()); diff --git a/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/filter/ValidateCodeGatewayFilter.java b/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/filter/ValidateCodeGatewayFilter.java index dc50d4c4f..cfac35ecb 100644 --- a/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/filter/ValidateCodeGatewayFilter.java +++ b/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/filter/ValidateCodeGatewayFilter.java @@ -102,8 +102,8 @@ public class ValidateCodeGatewayFilter extends AbstractGatewayFilterFactory { response.getHeaders().setContentType(MediaType.APPLICATION_JSON); response.setStatusCode(HttpStatus.PRECONDITION_REQUIRED); try { - return response.writeWith(Mono.just( - response.bufferFactory().wrap(objectMapper.writeValueAsBytes(R.failed(e.getMessage()))))); + return response.writeWith(Mono + .just(response.bufferFactory().wrap(objectMapper.writeValueAsBytes(R.failed(e.getMessage()))))); } catch (JsonProcessingException e1) { log.error("对象输出异常", e1); diff --git a/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/handler/ImageCodeCheckHandler.java b/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/handler/ImageCodeCheckHandler.java index 003d2328b..aa4d37d70 100644 --- a/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/handler/ImageCodeCheckHandler.java +++ b/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/handler/ImageCodeCheckHandler.java @@ -58,8 +58,9 @@ public class ImageCodeCheckHandler implements HandlerFunction { CaptchaService captchaService = SpringContextHolder.getBean(CaptchaService.class); ResponseModel responseModel = captchaService.check(vo); - return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON) - .body(BodyInserters.fromValue(objectMapper.writeValueAsString(R.ok(responseModel)))); + return ServerResponse.status(HttpStatus.OK) + .contentType(MediaType.APPLICATION_JSON) + .body(BodyInserters.fromValue(objectMapper.writeValueAsString(R.ok(responseModel)))); } } diff --git a/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/handler/ImageCodeCreateHandler.java b/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/handler/ImageCodeCreateHandler.java index edd33974d..a65a38a1b 100644 --- a/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/handler/ImageCodeCreateHandler.java +++ b/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/handler/ImageCodeCreateHandler.java @@ -55,8 +55,9 @@ public class ImageCodeCreateHandler implements HandlerFunction { CaptchaService captchaService = SpringContextHolder.getBean(CaptchaService.class); ResponseModel responseModel = captchaService.get(vo); - return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON) - .body(BodyInserters.fromValue(objectMapper.writeValueAsString(R.ok(responseModel)))); + return ServerResponse.status(HttpStatus.OK) + .contentType(MediaType.APPLICATION_JSON) + .body(BodyInserters.fromValue(objectMapper.writeValueAsString(R.ok(responseModel)))); } } diff --git a/pigx-register/src/main/java/com/alibaba/nacos/console/controller/HealthController.java b/pigx-register/src/main/java/com/alibaba/nacos/console/controller/HealthController.java index 6799a0bce..2b088165d 100644 --- a/pigx-register/src/main/java/com/alibaba/nacos/console/controller/HealthController.java +++ b/pigx-register/src/main/java/com/alibaba/nacos/console/controller/HealthController.java @@ -77,7 +77,7 @@ public class HealthController { if (!isConfigReadiness && !isNamingReadiness) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) - .body("Config and Naming are not in readiness"); + .body("Config and Naming are not in readiness"); } if (!isConfigReadiness) { diff --git a/pigx-register/src/main/java/com/alibaba/nacos/console/exception/ConsoleExceptionHandler.java b/pigx-register/src/main/java/com/alibaba/nacos/console/exception/ConsoleExceptionHandler.java index 30a792c09..fdba59104 100644 --- a/pigx-register/src/main/java/com/alibaba/nacos/console/exception/ConsoleExceptionHandler.java +++ b/pigx-register/src/main/java/com/alibaba/nacos/console/exception/ConsoleExceptionHandler.java @@ -57,7 +57,7 @@ public class ConsoleExceptionHandler { LOGGER.error("CONSOLE {}", uri, e); if (uri.contains(Commons.NACOS_SERVER_VERSION_V2)) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) - .body(RestResultUtils.failed(ExceptionUtil.getAllExceptionMsg(e))); + .body(RestResultUtils.failed(ExceptionUtil.getAllExceptionMsg(e))); } return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ExceptionUtil.getAllExceptionMsg(e)); } diff --git a/pigx-register/src/main/java/com/alibaba/nacos/console/exception/NacosApiExceptionHandler.java b/pigx-register/src/main/java/com/alibaba/nacos/console/exception/NacosApiExceptionHandler.java index c73e8f8e0..c704dd0f1 100644 --- a/pigx-register/src/main/java/com/alibaba/nacos/console/exception/NacosApiExceptionHandler.java +++ b/pigx-register/src/main/java/com/alibaba/nacos/console/exception/NacosApiExceptionHandler.java @@ -59,7 +59,7 @@ public class NacosApiExceptionHandler { public ResponseEntity> handleNacosApiException(NacosApiException e) { LOGGER.error("got exception. {} {}", e.getErrAbstract(), e.getErrMsg()); return ResponseEntity.status(e.getErrCode()) - .body(new Result<>(e.getDetailErrCode(), e.getErrAbstract(), e.getErrMsg())); + .body(new Result<>(e.getDetailErrCode(), e.getErrAbstract(), e.getErrMsg())); } @ExceptionHandler(NacosException.class) diff --git a/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/RemoteDeptService.java b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/RemoteDeptService.java new file mode 100644 index 000000000..16f69e18f --- /dev/null +++ b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/RemoteDeptService.java @@ -0,0 +1,44 @@ +/* + * + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + * + */ + +package com.pig4cloud.pigx.admin.api.feign; + +import com.pig4cloud.pigx.admin.api.entity.SysDept; +import com.pig4cloud.pigx.common.core.constant.ServiceNameConstants; +import com.pig4cloud.pigx.common.core.util.R; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; + +import java.util.List; + +/** + * @author lengleng + * @date 2018/6/22 + */ +@FeignClient(contextId = "remoteDeptService", value = ServiceNameConstants.UPMS_SERVICE) +public interface RemoteDeptService { + + /** + * 获取所有部门接口 + * @return R 返回结果对象,包含所有部门信息列表 + */ + @GetMapping("/dept/list") + R> getAllDept(); + +} diff --git a/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/RemoteRoleService.java b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/RemoteRoleService.java new file mode 100644 index 000000000..f34485dbc --- /dev/null +++ b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/RemoteRoleService.java @@ -0,0 +1,44 @@ +/* + * + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + * + */ + +package com.pig4cloud.pigx.admin.api.feign; + +import com.pig4cloud.pigx.admin.api.entity.SysRole; +import com.pig4cloud.pigx.common.core.constant.ServiceNameConstants; +import com.pig4cloud.pigx.common.core.util.R; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; + +import java.util.List; + +/** + * @author lengleng + * @date 2018/6/22 + */ +@FeignClient(contextId = "remoteRoleService", value = ServiceNameConstants.UPMS_SERVICE) +public interface RemoteRoleService { + + /** + * 获取所有部门接口 + * @return R 返回结果对象,包含所有部门信息列表 + */ + @GetMapping("/role/list") + R> getAllRole(); + +} diff --git a/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/RemoteUserService.java b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/RemoteUserService.java index b437fd05c..4b77182e1 100644 --- a/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/RemoteUserService.java +++ b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/feign/RemoteUserService.java @@ -25,10 +25,7 @@ import com.pig4cloud.pigx.common.core.constant.SecurityConstants; import com.pig4cloud.pigx.common.core.constant.ServiceNameConstants; import com.pig4cloud.pigx.common.core.util.R; import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.*; import java.util.List; @@ -48,6 +45,14 @@ public interface RemoteUserService { @GetMapping("/user/info/{username}") R info(@PathVariable("username") String username, @RequestHeader(SecurityConstants.FROM) String from); + /** + * 根据用户ID获取用户 + * @param userId ID + * @return SysUser + */ + @GetMapping("/user/details/{userId}") + R getUserById(@PathVariable("userId") Long userId); + /** * 通过社交账号或手机号查询用户、角色信息 * @param inStr appid@code @@ -74,4 +79,28 @@ public interface RemoteUserService { @PutMapping("/user/lock/{username}") R lockUser(@PathVariable("username") String username, @RequestHeader(SecurityConstants.FROM) String from); + /** + * 根据角色ID查询用户列表 + * @param roleIdList 角色ID列表 + * @return 用户ID列表 + */ + @GetMapping("/user/getUserIdListByRoleIdList") + R> getUserIdListByRoleIdList(@RequestParam("roleIdList") List roleIdList); + + /** + * 根据部门ID列表获取用户ID列表接口 + * @param deptIdList 部门ID列表 + * @return 用户ID列表 + */ + @GetMapping("/user/getUserIdListByDeptIdList") + R> getUserIdListByDeptIdList(@RequestParam("deptIdList") List deptIdList); + + /** + * 通过用户名查询用户列表 + * @param userName 用户名 + * @return 用户列表 + */ + @GetMapping("/user/getUserListByUserName") + R> getUserListByUserName(@RequestParam("username") String userName); + } diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/DemoParentDTO.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/DemoParentDTO.java new file mode 100644 index 000000000..9ba333902 --- /dev/null +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/DemoParentDTO.java @@ -0,0 +1,22 @@ +package com.pig4cloud.pigx.admin.controller; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * @author lengleng + * @date 2023/7/19 + */ +@Schema(description = "审计记录表") +public class DemoParentDTO { + + private ParentDTO parentDTO1; + + @Schema(description = "审计记录表") + private ParentDTO parentDTO2; + + @Schema(description = "审计记录表") + public class ParentDTO { + + } + +} diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysClientController.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysClientController.java index e51def082..3116fd275 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysClientController.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysClientController.java @@ -72,7 +72,7 @@ public class SysClientController { @GetMapping("/{clientId}") public R getByClientId(@PathVariable String clientId) { SysOauthClientDetails details = clientDetailsService - .getOne(Wrappers.lambdaQuery().eq(SysOauthClientDetails::getClientId, clientId)); + .getOne(Wrappers.lambdaQuery().eq(SysOauthClientDetails::getClientId, clientId)); String information = details.getAdditionalInformation(); String captchaFlag = JSONUtil.parseObj(information).getStr(CommonConstants.CAPTCHA_FLAG); String encFlag = JSONUtil.parseObj(information).getStr(CommonConstants.ENC_FLAG); @@ -95,10 +95,10 @@ public class SysClientController { public R getOauthClientDetailsPage(@ParameterObject Page page, @ParameterObject SysOauthClientDetails sysOauthClientDetails) { LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .like(StrUtil.isNotBlank(sysOauthClientDetails.getClientId()), SysOauthClientDetails::getClientId, - sysOauthClientDetails.getClientId()) - .like(StrUtil.isNotBlank(sysOauthClientDetails.getClientSecret()), - SysOauthClientDetails::getClientSecret, sysOauthClientDetails.getClientSecret()); + .like(StrUtil.isNotBlank(sysOauthClientDetails.getClientId()), SysOauthClientDetails::getClientId, + sysOauthClientDetails.getClientId()) + .like(StrUtil.isNotBlank(sysOauthClientDetails.getClientSecret()), SysOauthClientDetails::getClientSecret, + sysOauthClientDetails.getClientSecret()); return R.ok(clientDetailsService.page(page, wrapper)); } diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysDeptController.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysDeptController.java index 4b93249f6..c8d55a13f 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysDeptController.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysDeptController.java @@ -79,8 +79,8 @@ public class SysDeptController { * @return 树形菜单 */ @GetMapping(value = "/tree") - public R getTree(String deptName) { - return R.ok(sysDeptService.selectTree(deptName)); + public R getTree(String deptName, Long parentId) { + return R.ok(sysDeptService.selectTree(deptName, parentId)); } /** diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysDictController.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysDictController.java index 3c6b8482d..9c500fb17 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysDictController.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysDictController.java @@ -92,9 +92,8 @@ public class SysDictController { public R getDictPage(@ParameterObject Page page, @ParameterObject SysDict sysDict) { return R.ok(sysDictService.page(page, Wrappers.lambdaQuery() - .eq(StrUtil.isNotBlank(sysDict.getSystemFlag()), SysDict::getSystemFlag, - sysDict.getSystemFlag()) - .like(StrUtil.isNotBlank(sysDict.getDictType()), SysDict::getDictType, sysDict.getDictType()))); + .eq(StrUtil.isNotBlank(sysDict.getSystemFlag()), SysDict::getSystemFlag, sysDict.getSystemFlag()) + .like(StrUtil.isNotBlank(sysDict.getDictType()), SysDict::getDictType, sysDict.getDictType()))); } /** @@ -153,9 +152,10 @@ public class SysDictController { */ @GetMapping("/list") public R getDictList(String name) { - return R.ok(sysDictService - .list(Wrappers.lambdaQuery().like(StrUtil.isNotBlank(name), SysDict::getDictType, name).or() - .like(StrUtil.isNotBlank(name), SysDict::getDescription, name))); + return R.ok(sysDictService.list(Wrappers.lambdaQuery() + .like(StrUtil.isNotBlank(name), SysDict::getDictType, name) + .or() + .like(StrUtil.isNotBlank(name), SysDict::getDescription, name))); } /** diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysFileController.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysFileController.java index 17ba03c4f..1e9af99f4 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysFileController.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysFileController.java @@ -66,7 +66,7 @@ public class SysFileController { @GetMapping("/page") public R getSysFilePage(@ParameterObject Page page, @ParameterObject SysFile sysFile) { LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .like(StrUtil.isNotBlank(sysFile.getOriginal()), SysFile::getOriginal, sysFile.getOriginal()); + .like(StrUtil.isNotBlank(sysFile.getOriginal()), SysFile::getOriginal, sysFile.getOriginal()); return R.ok(sysFileService.page(page, wrapper)); } diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysMenuController.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysMenuController.java index bbe8db7ad..5b94aa0bb 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysMenuController.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysMenuController.java @@ -81,8 +81,8 @@ public class SysMenuController { */ @GetMapping("/tree/{roleId}") public R getRoleTree(@PathVariable Long roleId) { - return R.ok( - sysMenuService.findMenuByRoleId(roleId).stream().map(SysMenu::getMenuId).collect(Collectors.toList())); + return R + .ok(sysMenuService.findMenuByRoleId(roleId).stream().map(SysMenu::getMenuId).collect(Collectors.toList())); } /** diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysPostController.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysPostController.java index 05dece784..b5a4ba0bf 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysPostController.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysPostController.java @@ -75,7 +75,7 @@ public class SysPostController { @PreAuthorize("@pms.hasPermission('sys_post_view')") public R getSysPostPage(@ParameterObject Page page, @ParameterObject SysPost sysPost) { return R.ok(sysPostService.page(page, Wrappers.lambdaQuery() - .like(StrUtil.isNotBlank(sysPost.getPostName()), SysPost::getPostName, sysPost.getPostName()))); + .like(StrUtil.isNotBlank(sysPost.getPostName()), SysPost::getPostName, sysPost.getPostName()))); } /** diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysPublicParamController.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysPublicParamController.java index 40d23f38e..e6a694464 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysPublicParamController.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysPublicParamController.java @@ -75,12 +75,12 @@ public class SysPublicParamController { @GetMapping("/page") public R getSysPublicParamPage(@ParameterObject Page page, @ParameterObject SysPublicParam sysPublicParam) { LambdaUpdateWrapper wrapper = Wrappers.lambdaUpdate() - .like(StrUtil.isNotBlank(sysPublicParam.getPublicName()), SysPublicParam::getPublicName, - sysPublicParam.getPublicName()) - .like(StrUtil.isNotBlank(sysPublicParam.getPublicKey()), SysPublicParam::getPublicKey, - sysPublicParam.getPublicKey()) - .eq(StrUtil.isNotBlank(sysPublicParam.getSystemFlag()), SysPublicParam::getSystemFlag, - sysPublicParam.getSystemFlag()); + .like(StrUtil.isNotBlank(sysPublicParam.getPublicName()), SysPublicParam::getPublicName, + sysPublicParam.getPublicName()) + .like(StrUtil.isNotBlank(sysPublicParam.getPublicKey()), SysPublicParam::getPublicKey, + sysPublicParam.getPublicKey()) + .eq(StrUtil.isNotBlank(sysPublicParam.getSystemFlag()), SysPublicParam::getSystemFlag, + sysPublicParam.getSystemFlag()); return R.ok(sysPublicParamService.page(page, wrapper)); } diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysRoleController.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysRoleController.java index 2b5c75e51..23b768745 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysRoleController.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysRoleController.java @@ -135,7 +135,7 @@ public class SysRoleController { @GetMapping("/page") public R getRolePage(Page page, SysRole role) { return R.ok(sysRoleService.page(page, Wrappers.lambdaQuery() - .like(StrUtil.isNotBlank(role.getRoleName()), SysRole::getRoleName, role.getRoleName()))); + .like(StrUtil.isNotBlank(role.getRoleName()), SysRole::getRoleName, role.getRoleName()))); } /** diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysSocialDetailsController.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysSocialDetailsController.java index 1d55675bf..a663ad858 100755 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysSocialDetailsController.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysSocialDetailsController.java @@ -72,7 +72,7 @@ public class SysSocialDetailsController { @GetMapping("/{type}") public R getByType(@PathVariable("type") String type) { return R.ok(sysSocialDetailsService - .list(Wrappers.lambdaQuery().eq(SysSocialDetails::getType, type))); + .list(Wrappers.lambdaQuery().eq(SysSocialDetails::getType, type))); } @GetMapping("/getById/{id}") diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysSystemInfoController.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysSystemInfoController.java index f71476a58..3a7ea8554 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysSystemInfoController.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysSystemInfoController.java @@ -32,7 +32,7 @@ public class SysSystemInfoController { public R cache() { Properties info = (Properties) redisTemplate.execute((RedisCallback) RedisServerCommands::info); Properties commandStats = (Properties) redisTemplate - .execute((RedisCallback) connection -> connection.info("commandstats")); + .execute((RedisCallback) connection -> connection.info("commandstats")); Object dbSize = redisTemplate.execute((RedisCallback) RedisServerCommands::dbSize); if (commandStats == null) { diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysTenantController.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysTenantController.java index 853e984d3..54f66101d 100755 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysTenantController.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysTenantController.java @@ -65,7 +65,7 @@ public class SysTenantController { @GetMapping("/page") public R getSysTenantPage(@ParameterObject Page page, @ParameterObject SysTenant sysTenant) { return R.ok(sysTenantService.page(page, Wrappers.lambdaQuery() - .like(StrUtil.isNotBlank(sysTenant.getName()), SysTenant::getName, sysTenant.getName()))); + .like(StrUtil.isNotBlank(sysTenant.getName()), SysTenant::getName, sysTenant.getName()))); } /** @@ -136,9 +136,11 @@ public class SysTenantController { @Inner(value = false) @GetMapping("/list") public R list() { - List tenants = sysTenantService.getNormalTenant().stream() - .filter(tenant -> tenant.getStartTime().isBefore(LocalDateTime.now())) - .filter(tenant -> tenant.getEndTime().isAfter(LocalDateTime.now())).collect(Collectors.toList()); + List tenants = sysTenantService.getNormalTenant() + .stream() + .filter(tenant -> tenant.getStartTime().isBefore(LocalDateTime.now())) + .filter(tenant -> tenant.getEndTime().isAfter(LocalDateTime.now())) + .collect(Collectors.toList()); return R.ok(tenants); } diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysTenantMenuController.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysTenantMenuController.java index 022b79b4a..6c6b6ddd4 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysTenantMenuController.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysTenantMenuController.java @@ -103,8 +103,8 @@ public class SysTenantMenuController { @Inner(value = false) @GetMapping("/list") public R list() { - List tenants = sysTenantMenuService.list( - Wrappers.lambdaQuery().eq(SysTenantMenu::getStatus, CommonConstants.STATUS_NORMAL)); + List tenants = sysTenantMenuService + .list(Wrappers.lambdaQuery().eq(SysTenantMenu::getStatus, CommonConstants.STATUS_NORMAL)); return R.ok(tenants); } diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysUserController.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysUserController.java index 93fc21863..e504d16f1 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysUserController.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysUserController.java @@ -19,6 +19,7 @@ package com.pig4cloud.pigx.admin.controller; +import cn.hutool.core.collection.CollUtil; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.pig4cloud.pigx.admin.api.dto.UserDTO; @@ -213,6 +214,11 @@ public class SysUserController { return userService.lockUser(username); } + /** + * 修改密码接口 + * @param userDto 用户DTO对象,包含需要修改密码的用户信息 + * @return R 返回结果对象,包含修改密码操作的结果信息 + */ @PutMapping("/password") public R password(@RequestBody UserDTO userDto) { String username = SecurityUtils.getUser().getUsername(); @@ -220,14 +226,54 @@ public class SysUserController { return userService.changePassword(userDto); } + /** + * 解绑定接口 + * @param type 需要解绑定的类型 + * @return R 返回结果对象,包含解绑定操作的结果信息 + */ @PostMapping("/unbinding") public R unbinding(String type) { return userService.unbinding(type); } + /** + * 校验密码接口 + * @param password 需要校验的密码 + * @return R 返回结果对象,包含校验密码操作的结果信息 + */ @PostMapping("/check") public R check(String password) { return userService.checkPassword(password); } + /** + * 根据角色ID列表获取用户ID列表接口 + * @param roleIdList 角色ID列表 + * @return R 返回结果对象,包含根据角色ID列表获取到的用户ID列表信息 + */ + @GetMapping("/getUserIdListByRoleIdList") + public R> getUserIdListByRoleIdList(Long[] roleIdList) { + return R.ok(userService.listUserIdByRoleIds(CollUtil.toList(roleIdList))); + } + + /** + * 根据部门ID列表获取用户ID列表接口 + * @param deptIdList 部门ID列表 + * @return R 返回结果对象,包含根据部门ID列表获取到的用户ID列表信息 + */ + @GetMapping("/getUserIdListByDeptIdList") + public R> getUserIdListByDeptIdList(Long[] deptIdList) { + return R.ok(userService.listUserIdByDeptIds(CollUtil.toList(deptIdList))); + } + + /** + * 根据用户名获取用户列表 + * @param username 用户名 + * @return 用户列表 + */ + @GetMapping("/getUserListByUserName") + public R> getUserListByUserName(String username) { + return R.ok(userService.list(Wrappers.lambdaQuery().like(SysUser::getUsername, username))); + } + } diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/SysDeptService.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/SysDeptService.java index 80293f3a6..8c471b000 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/SysDeptService.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/SysDeptService.java @@ -41,9 +41,10 @@ public interface SysDeptService extends IService { /** * 查询部门树菜单 * @param deptName 部门名称 + * @param parentId * @return 树 */ - List> selectTree(String deptName); + List> selectTree(String deptName, Long parentId); /** * 删除部门 diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/SysUserService.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/SysUserService.java index c37cb7c06..266f1c3ad 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/SysUserService.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/SysUserService.java @@ -124,10 +124,39 @@ public interface SysUserService extends IService { */ R lockUser(String username); + /** + * 修改密码接口 + * @param userDto 用户DTO对象,包含需要修改密码的用户信息 + * @return R 返回结果对象,包含修改密码操作的结果信息 + */ R changePassword(UserDTO userDto); + /** + * 解绑定接口 + * @param type 需要解绑定的类型 + * @return R 返回结果对象,包含解绑定操作的结果信息 + */ R unbinding(String type); + /** + * 校验密码接口 + * @param password 需要校验的密码 + * @return R 返回结果对象,包含校验密码操作的结果信息 + */ R checkPassword(String password); + /** + * 根据角色ID列表获取用户ID列表接口 + * @param roleIdList 角色ID列表 + * @return List 返回结果对象,包含根据角色ID列表获取到的用户ID列表信息 + */ + List listUserIdByRoleIds(List roleIdList); + + /** + * 根据部门ID列表获取用户ID列表接口 + * @param deptIdList 部门ID列表 + * @return List 返回结果对象,包含根据部门ID列表获取到的用户ID列表信息 + */ + List listUserIdByDeptIds(List deptIdList); + } diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/ConnectServiceImpl.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/ConnectServiceImpl.java index c15cfcb01..bda4ab99c 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/ConnectServiceImpl.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/ConnectServiceImpl.java @@ -133,8 +133,9 @@ public class ConnectServiceImpl implements ConnectService { JSONObject userResult = JSONUtil.parseObj(userGetResponse.getBody()); JSONObject userObj = JSONUtil.parseObj(userResult.get("result")); - boolean exist = users.stream().filter(user -> StrUtil.isNotBlank(user.getPhone())) - .anyMatch(user -> user.getPhone().equals(userObj.getStr("mobile"))); + boolean exist = users.stream() + .filter(user -> StrUtil.isNotBlank(user.getPhone())) + .anyMatch(user -> user.getPhone().equals(userObj.getStr("mobile"))); if (exist || StrUtil.isBlank(userObj.getStr("mobile"))) { log.info("用户已存在或手机号不合法 {}", userid); @@ -188,15 +189,16 @@ public class ConnectServiceImpl implements ConnectService { // 数据库中现有的部门 List deptList = sysDeptService.list(Wrappers.emptyWrapper()); departList.stream() - .filter(depart -> deptList.stream().noneMatch(sysDept -> depart.getName().equals(sysDept.getName()))) - .map(dept -> { - SysDept sysDept = new SysDept(); - sysDept.setName(dept.getName()); - sysDept.setDeptId(dept.getId()); - sysDept.setParentId(dept.getParentId()); - sysDept.setSortOrder(dept.getOrder().intValue()); - return sysDept; - }).forEach(sysDeptService::save); + .filter(depart -> deptList.stream().noneMatch(sysDept -> depart.getName().equals(sysDept.getName()))) + .map(dept -> { + SysDept sysDept = new SysDept(); + sysDept.setName(dept.getName()); + sysDept.setDeptId(dept.getId()); + sysDept.setParentId(dept.getParentId()); + sysDept.setSortOrder(dept.getOrder().intValue()); + return sysDept; + }) + .forEach(sysDeptService::save); return R.ok(); } @@ -226,8 +228,9 @@ public class ConnectServiceImpl implements ConnectService { List userList = sysUserService.list(Wrappers.emptyWrapper()); for (WxCpUser cpUser : cpUserList) { - boolean exist = userList.stream().filter(user -> StrUtil.isNotBlank(user.getPhone())) - .anyMatch(user -> user.getPhone().equals(cpUser.getMobile())); + boolean exist = userList.stream() + .filter(user -> StrUtil.isNotBlank(user.getPhone())) + .anyMatch(user -> user.getPhone().equals(cpUser.getMobile())); if (exist || StrUtil.isBlank(cpUser.getMobile())) { log.info("用户已存在或手机号不合法跳过 {}", cpUser); continue; @@ -250,7 +253,7 @@ public class ConnectServiceImpl implements ConnectService { private String getDingAccessToken() { SysSocialDetails dingTalk = sysSocialDetailsMapper.selectOne(Wrappers.lambdaQuery() - .eq(SysSocialDetails::getType, LoginTypeEnum.DINGTALK.getType())); + .eq(SysSocialDetails::getType, LoginTypeEnum.DINGTALK.getType())); DingTalkClient client = new DefaultDingTalkClient(SecurityConstants.DING_OLD_GET_TOKEN); OapiGettokenRequest request = new OapiGettokenRequest(); @@ -269,7 +272,7 @@ public class ConnectServiceImpl implements ConnectService { public WxCpDefaultConfigImpl getCpConfig() { SysSocialDetails cp = sysSocialDetailsMapper.selectOne(Wrappers.lambdaQuery() - .eq(SysSocialDetails::getType, LoginTypeEnum.WEIXIN_CP.getType())); + .eq(SysSocialDetails::getType, LoginTypeEnum.WEIXIN_CP.getType())); WxCpDefaultConfigImpl config = new WxCpDefaultConfigImpl(); config.setCorpId(cp.getAppId()); // 设置微信企业号的appid @@ -303,14 +306,15 @@ public class ConnectServiceImpl implements ConnectService { // 过滤出数据库存在的部门 List depts = resultList.stream() - .filter(dept -> deptList.stream().noneMatch(sysDept -> sysDept.getName().equals(dept.get("name")))) - .map(dept -> { - SysDept sysDept = new SysDept(); - sysDept.setName(Convert.toStr(dept.get("name"))); - sysDept.setDeptId(Convert.toLong(dept.get("dept_id"))); - sysDept.setParentId(Convert.toLong(dept.get("parent_id"))); - return sysDept; - }).collect(Collectors.toList()); + .filter(dept -> deptList.stream().noneMatch(sysDept -> sysDept.getName().equals(dept.get("name")))) + .map(dept -> { + SysDept sysDept = new SysDept(); + sysDept.setName(Convert.toStr(dept.get("name"))); + sysDept.setDeptId(Convert.toLong(dept.get("dept_id"))); + sysDept.setParentId(Convert.toLong(dept.get("parent_id"))); + return sysDept; + }) + .collect(Collectors.toList()); // 递归查询下一级 if (CollectionUtils.isNotEmpty(depts)) { diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/MobileServiceImpl.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/MobileServiceImpl.java index cf85d076c..e8d487138 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/MobileServiceImpl.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/MobileServiceImpl.java @@ -61,7 +61,7 @@ public class MobileServiceImpl implements MobileService { @Override public R sendSmsCode(String mobile) { List userList = userMapper - .selectList(Wrappers.query().lambda().eq(SysUser::getPhone, mobile)); + .selectList(Wrappers.query().lambda().eq(SysUser::getPhone, mobile)); if (CollUtil.isEmpty(userList)) { log.info("手机号未注册:{}", mobile); @@ -69,7 +69,7 @@ public class MobileServiceImpl implements MobileService { } Object codeObj = redisTemplate.opsForValue() - .get(CacheConstants.DEFAULT_CODE_KEY + LoginTypeEnum.SMS.getType() + StringPool.AT + mobile); + .get(CacheConstants.DEFAULT_CODE_KEY + LoginTypeEnum.SMS.getType() + StringPool.AT + mobile); if (codeObj != null) { log.info("手机号验证码未过期:{},{}", mobile, codeObj); @@ -78,9 +78,9 @@ public class MobileServiceImpl implements MobileService { String code = RandomUtil.randomNumbers(Integer.parseInt(SecurityConstants.CODE_SIZE)); log.debug("手机号生成验证码成功:{},{}", mobile, code); - redisTemplate.opsForValue().set( - CacheConstants.DEFAULT_CODE_KEY + LoginTypeEnum.SMS.getType() + StringPool.AT + mobile, code, - SecurityConstants.CODE_TIME, TimeUnit.SECONDS); + redisTemplate.opsForValue() + .set(CacheConstants.DEFAULT_CODE_KEY + LoginTypeEnum.SMS.getType() + StringPool.AT + mobile, code, + SecurityConstants.CODE_TIME, TimeUnit.SECONDS); return R.ok(Boolean.TRUE, code); } diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysDeptServiceImpl.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysDeptServiceImpl.java index d4cf8fcaa..b2733cf64 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysDeptServiceImpl.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysDeptServiceImpl.java @@ -75,34 +75,41 @@ public class SysDeptServiceImpl extends ServiceImpl impl /** * 查询全部部门树 * @param deptName + * @param parentId * @return 树 部门名称 */ @Override - public List> selectTree(String deptName) { + public List> selectTree(String deptName, Long parentId) { // 查询全部部门 - List deptAllList = deptMapper.selectList( - Wrappers.lambdaQuery().like(StrUtil.isNotBlank(deptName), SysDept::getName, deptName)); + List deptAllList = deptMapper + .selectList(Wrappers.lambdaQuery().like(StrUtil.isNotBlank(deptName), SysDept::getName, deptName)); // 查询数据权限内部门 - List deptOwnIdList = deptMapper.selectListByScope( - Wrappers.lambdaQuery().like(StrUtil.isNotBlank(deptName), SysDept::getName, deptName), - DataScope.of()).stream().map(SysDept::getDeptId).collect(Collectors.toList()); + List deptOwnIdList = deptMapper + .selectListByScope( + Wrappers.lambdaQuery().like(StrUtil.isNotBlank(deptName), SysDept::getName, deptName), + DataScope.of()) + .stream() + .map(SysDept::getDeptId) + .toList(); // 权限内部门 List> collect = deptAllList.stream() - .filter(dept -> dept.getDeptId().intValue() != dept.getParentId()) - .sorted(Comparator.comparingInt(SysDept::getSortOrder)).map(dept -> { - TreeNode treeNode = new TreeNode(); - treeNode.setId(dept.getDeptId()); - treeNode.setParentId(dept.getParentId()); - treeNode.setName(dept.getName()); - treeNode.setWeight(dept.getSortOrder()); - // 有权限不返回标识 - Map extra = new HashMap<>(8); - extra.put("isLock", !deptOwnIdList.contains(dept.getDeptId())); - extra.put("createTime", dept.getCreateTime()); - treeNode.setExtra(extra); - return treeNode; - }).collect(Collectors.toList()); + .filter(dept -> dept.getDeptId().intValue() != dept.getParentId()) + .sorted(Comparator.comparingInt(SysDept::getSortOrder)) + .map(dept -> { + TreeNode treeNode = new TreeNode<>(); + treeNode.setId(dept.getDeptId()); + treeNode.setParentId(dept.getParentId()); + treeNode.setName(dept.getName()); + treeNode.setWeight(dept.getSortOrder()); + // 有权限不返回标识 + Map extra = new HashMap<>(8); + extra.put("isLock", !deptOwnIdList.contains(dept.getDeptId())); + extra.put("createTime", dept.getCreateTime()); + treeNode.setExtra(extra); + return treeNode; + }) + .collect(Collectors.toList()); // 模糊查询 不组装树结构 直接返回 表格方便编辑 if (StrUtil.isNotBlank(deptName)) { @@ -114,7 +121,7 @@ public class SysDeptServiceImpl extends ServiceImpl impl }).collect(Collectors.toList()); } - return TreeUtil.build(collect, 0L); + return TreeUtil.build(collect, parentId == null ? 0 : parentId); } /** @@ -127,8 +134,11 @@ public class SysDeptServiceImpl extends ServiceImpl impl List deptExcelVos = list.stream().map(item -> { DeptExcelVo deptExcelVo = new DeptExcelVo(); deptExcelVo.setName(item.getName()); - Optional first = this.list().stream().filter(it -> item.getParentId().equals(it.getDeptId())) - .map(SysDept::getName).findFirst(); + Optional first = this.list() + .stream() + .filter(it -> item.getParentId().equals(it.getDeptId())) + .map(SysDept::getName) + .findFirst(); deptExcelVo.setParentName(first.orElse("根部门")); deptExcelVo.setSortOrder(item.getSortOrder()); return deptExcelVo; @@ -188,8 +198,9 @@ public class SysDeptServiceImpl extends ServiceImpl impl recursiveDept(allDeptList, deptId, resDeptList); // 添加当前节点 - resDeptList.addAll(allDeptList.stream().filter(sysDept -> deptId.equals(sysDept.getDeptId())) - .collect(Collectors.toList())); + resDeptList.addAll(allDeptList.stream() + .filter(sysDept -> deptId.equals(sysDept.getDeptId())) + .collect(Collectors.toList())); return resDeptList; } diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysDictServiceImpl.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysDictServiceImpl.java index c62e3912f..1b4bfa95e 100755 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysDictServiceImpl.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysDictServiceImpl.java @@ -59,9 +59,11 @@ public class SysDictServiceImpl extends ServiceImpl impl @CacheEvict(value = CacheConstants.DICT_DETAILS, allEntries = true) public R removeDictByIds(Long[] ids) { - List dictIdList = baseMapper.selectBatchIds(CollUtil.toList(ids)).stream() - .filter(sysDict -> !sysDict.getSystemFlag().equals(DictTypeEnum.SYSTEM.getType()))// 系统内置类型不删除 - .map(SysDict::getId).collect(Collectors.toList()); + List dictIdList = baseMapper.selectBatchIds(CollUtil.toList(ids)) + .stream() + .filter(sysDict -> !sysDict.getSystemFlag().equals(DictTypeEnum.SYSTEM.getType()))// 系统内置类型不删除 + .map(SysDict::getId) + .collect(Collectors.toList()); baseMapper.deleteBatchIds(dictIdList); diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysLogServiceImpl.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysLogServiceImpl.java index b8d0eb297..6b6effd3f 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysLogServiceImpl.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysLogServiceImpl.java @@ -82,8 +82,8 @@ public class SysLogServiceImpl extends ServiceImpl impleme } if (ArrayUtil.isNotEmpty(sysLog.getCreateTime())) { - wrapper.ge(SysLog::getCreateTime, sysLog.getCreateTime()[0]).le(SysLog::getCreateTime, - sysLog.getCreateTime()[1]); + wrapper.ge(SysLog::getCreateTime, sysLog.getCreateTime()[0]) + .le(SysLog::getCreateTime, sysLog.getCreateTime()[1]); } return baseMapper.selectPage(page, wrapper); diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysMenuServiceImpl.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysMenuServiceImpl.java index 46b234a1a..117e479db 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysMenuServiceImpl.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysMenuServiceImpl.java @@ -109,10 +109,13 @@ public class SysMenuServiceImpl extends ServiceImpl impl Long parent = parentId == null ? CommonConstants.MENU_TREE_ROOT_ID : parentId; List> collect = baseMapper - .selectList(Wrappers.lambdaQuery() - .like(StrUtil.isNotBlank(menuName), SysMenu::getName, menuName) - .eq(StrUtil.isNotBlank(type), SysMenu::getMenuType, type).orderByAsc(SysMenu::getSortOrder)) - .stream().map(getNodeFunction()).collect(Collectors.toList()); + .selectList(Wrappers.lambdaQuery() + .like(StrUtil.isNotBlank(menuName), SysMenu::getName, menuName) + .eq(StrUtil.isNotBlank(type), SysMenu::getMenuType, type) + .orderByAsc(SysMenu::getSortOrder)) + .stream() + .map(getNodeFunction()) + .collect(Collectors.toList()); // 模糊查询 不组装树结构 直接返回 表格方便编辑 if (StrUtil.isNotBlank(menuName)) { diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysOauthClientDetailsServiceImpl.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysOauthClientDetailsServiceImpl.java index 2e625f041..408bbd3e9 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysOauthClientDetailsServiceImpl.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysOauthClientDetailsServiceImpl.java @@ -93,9 +93,9 @@ public class SysOauthClientDetailsServiceImpl extends ServiceImpl impl for (PostExcelVO excel : excelVOList) { Set errorMsg = new HashSet<>(); // 检验岗位名称或者岗位编码是否存在 - boolean existPost = postList.stream().anyMatch(post -> excel.getPostName().equals(post.getPostName()) - || excel.getPostCode().equals(post.getPostCode())); + boolean existPost = postList.stream() + .anyMatch(post -> excel.getPostName().equals(post.getPostName()) + || excel.getPostCode().equals(post.getPostCode())); if (existPost) { errorMsg.add(MsgUtils.getMessage(ErrorCodes.SYS_POST_NAMEORCODE_EXISTING, excel.getPostName(), diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysPublicParamServiceImpl.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysPublicParamServiceImpl.java index 09256a2a8..4610d4e15 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysPublicParamServiceImpl.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysPublicParamServiceImpl.java @@ -51,7 +51,7 @@ public class SysPublicParamServiceImpl extends ServiceImpllambdaQuery().eq(SysPublicParam::getPublicKey, publicKey)); + .selectOne(Wrappers.lambdaQuery().eq(SysPublicParam::getPublicKey, publicKey)); if (sysPublicParam != null) { return sysPublicParam.getPublicValue(); @@ -83,9 +83,11 @@ public class SysPublicParamServiceImpl extends ServiceImpl idList = this.baseMapper.selectBatchIds(CollUtil.toList(publicIds)).stream() - .filter(p -> !p.getSystemFlag().equals(DictTypeEnum.SYSTEM.getType()))// 系统内置的跳过不能删除 - .map(SysPublicParam::getPublicId).collect(Collectors.toList()); + List idList = this.baseMapper.selectBatchIds(CollUtil.toList(publicIds)) + .stream() + .filter(p -> !p.getSystemFlag().equals(DictTypeEnum.SYSTEM.getType()))// 系统内置的跳过不能删除 + .map(SysPublicParam::getPublicId) + .collect(Collectors.toList()); return R.ok(this.removeBatchByIds(idList)); } diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysRoleServiceImpl.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysRoleServiceImpl.java index 16fe89f92..9c0b76801 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysRoleServiceImpl.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysRoleServiceImpl.java @@ -91,7 +91,7 @@ public class SysRoleServiceImpl extends ServiceImpl impl @Transactional(rollbackFor = Exception.class) public Boolean removeRoleByIds(Long[] ids) { roleMenuService - .remove(Wrappers.update().lambda().in(SysRoleMenu::getRoleId, CollUtil.toList(ids))); + .remove(Wrappers.update().lambda().in(SysRoleMenu::getRoleId, CollUtil.toList(ids))); return this.removeBatchByIds(CollUtil.toList(ids)); } @@ -123,8 +123,9 @@ public class SysRoleServiceImpl extends ServiceImpl impl for (RoleExcelVO excel : excelVOList) { Set errorMsg = new HashSet<>(); // 检验角色名称或者角色编码是否存在 - boolean existRole = roleList.stream().anyMatch(sysRole -> excel.getRoleName().equals(sysRole.getRoleName()) - || excel.getRoleCode().equals(sysRole.getRoleCode())); + boolean existRole = roleList.stream() + .anyMatch(sysRole -> excel.getRoleName().equals(sysRole.getRoleName()) + || excel.getRoleCode().equals(sysRole.getRoleCode())); if (existRole) { errorMsg.add(MsgUtils.getMessage(ErrorCodes.SYS_ROLE_NAMEORCODE_EXISTING, excel.getRoleName(), diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysRouteConfServiceImpl.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysRouteConfServiceImpl.java index 52cef406e..019399db6 100755 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysRouteConfServiceImpl.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysRouteConfServiceImpl.java @@ -96,7 +96,7 @@ public class SysRouteConfServiceImpl extends ServiceImpl predicateDefinitionList = predicatesArray - .toList(PredicateDefinition.class); + .toList(PredicateDefinition.class); vo.setPredicates(predicateDefinitionList); } diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysTenantServiceImpl.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysTenantServiceImpl.java index 1d49c27da..792a2fadf 100755 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysTenantServiceImpl.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysTenantServiceImpl.java @@ -87,7 +87,7 @@ public class SysTenantServiceImpl extends ServiceImpl getNormalTenant() { return baseMapper - .selectList(Wrappers.lambdaQuery().eq(SysTenant::getStatus, CommonConstants.STATUS_NORMAL)); + .selectList(Wrappers.lambdaQuery().eq(SysTenant::getStatus, CommonConstants.STATUS_NORMAL)); } /** @@ -187,17 +187,20 @@ public class SysTenantServiceImpl extends ServiceImpl d.setId(null)).collect(Collectors.toList())); // 处理字典项最新关联的字典ID - List itemList = dictList.stream().flatMap(dict -> dictItemList.stream() - .filter(item -> item.getDictType().equals(dict.getDictType())).peek(item -> { + List itemList = dictList.stream() + .flatMap(dict -> dictItemList.stream() + .filter(item -> item.getDictType().equals(dict.getDictType())) + .peek(item -> { item.setDictId(dict.getId()); item.setId(null); - })).collect(Collectors.toList()); + })) + .collect(Collectors.toList()); // 插入客户端 clientServices.saveBatch(clientDetailsList.stream().peek(d -> d.setId(null)).collect(Collectors.toList())); // 插入系统配置 paramService - .saveBatch(publicParamList.stream().peek(d -> d.setPublicId(null)).collect(Collectors.toList())); + .saveBatch(publicParamList.stream().peek(d -> d.setPublicId(null)).collect(Collectors.toList())); return dictItemService.saveBatch(itemList); })); diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysUserServiceImpl.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysUserServiceImpl.java index 0ef47b365..192ef4545 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysUserServiceImpl.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysUserServiceImpl.java @@ -118,7 +118,7 @@ public class SysUserServiceImpl extends ServiceImpl impl String defaultRole = ParamResolver.getStr("USER_DEFAULT_ROLE"); // 默认角色 SysRole sysRole = sysRoleService - .getOne(Wrappers.lambdaQuery().eq(SysRole::getRoleCode, defaultRole)); + .getOne(Wrappers.lambdaQuery().eq(SysRole::getRoleCode, defaultRole)); userDto.setRole(Collections.singletonList(sysRole.getRoleId())); } @@ -142,16 +142,20 @@ public class SysUserServiceImpl extends ServiceImpl impl UserInfo userInfo = new UserInfo(); userInfo.setSysUser(sysUser); // 设置角色列表 (ID) - List roleIds = sysRoleService.findRolesByUserId(sysUser.getUserId()).stream().map(SysRole::getRoleId) - .collect(Collectors.toList()); + List roleIds = sysRoleService.findRolesByUserId(sysUser.getUserId()) + .stream() + .map(SysRole::getRoleId) + .collect(Collectors.toList()); userInfo.setRoles(ArrayUtil.toArray(roleIds, Long.class)); // 设置权限列表(menu.permission) Set permissions = new HashSet<>(); roleIds.forEach(roleId -> { - List permissionList = sysMenuService.findMenuByRoleId(roleId).stream() - .filter(menu -> StrUtil.isNotEmpty(menu.getPermission())).map(SysMenu::getPermission) - .collect(Collectors.toList()); + List permissionList = sysMenuService.findMenuByRoleId(roleId) + .stream() + .filter(menu -> StrUtil.isNotEmpty(menu.getPermission())) + .map(SysMenu::getPermission) + .collect(Collectors.toList()); permissions.addAll(permissionList); }); userInfo.setPermissions(ArrayUtil.toArray(permissions, String.class)); @@ -279,11 +283,15 @@ public class SysUserServiceImpl extends ServiceImpl impl List userExcelVOList = voList.stream().map(userVO -> { UserExcelVO excelVO = new UserExcelVO(); BeanUtils.copyProperties(userVO, excelVO); - String roleNameList = userVO.getRoleList().stream().map(SysRole::getRoleName) - .collect(Collectors.joining(StrUtil.COMMA)); + String roleNameList = userVO.getRoleList() + .stream() + .map(SysRole::getRoleName) + .collect(Collectors.joining(StrUtil.COMMA)); excelVO.setRoleNameList(roleNameList); - String postNameList = userVO.getPostList().stream().map(SysPost::getPostName) - .collect(Collectors.joining(StrUtil.COMMA)); + String postNameList = userVO.getPostList() + .stream() + .map(SysPost::getPostName) + .collect(Collectors.joining(StrUtil.COMMA)); excelVO.setPostNameList(postNameList); return excelVO; }).collect(Collectors.toList()); @@ -312,7 +320,7 @@ public class SysUserServiceImpl extends ServiceImpl impl Set errorMsg = new HashSet<>(); // 校验用户名是否存在 boolean exsitUserName = userList.stream() - .anyMatch(sysUser -> excel.getUsername().equals(sysUser.getUsername())); + .anyMatch(sysUser -> excel.getUsername().equals(sysUser.getUsername())); if (exsitUserName) { errorMsg.add(MsgUtils.getMessage(ErrorCodes.SYS_USER_USERNAME_EXISTING, excel.getUsername())); @@ -320,7 +328,8 @@ public class SysUserServiceImpl extends ServiceImpl impl // 判断输入的部门名称列表是否合法 Optional deptOptional = deptList.stream() - .filter(dept -> excel.getDeptName().equals(dept.getName())).findFirst(); + .filter(dept -> excel.getDeptName().equals(dept.getName())) + .findFirst(); if (!deptOptional.isPresent()) { errorMsg.add(MsgUtils.getMessage(ErrorCodes.SYS_DEPT_DEPTNAME_INEXISTENCE, excel.getDeptName())); } @@ -328,8 +337,8 @@ public class SysUserServiceImpl extends ServiceImpl impl // 判断输入的角色名称列表是否合法 List roleNameList = StrUtil.split(excel.getRoleNameList(), StrUtil.COMMA); List roleCollList = roleList.stream() - .filter(role -> roleNameList.stream().anyMatch(name -> role.getRoleName().equals(name))) - .collect(Collectors.toList()); + .filter(role -> roleNameList.stream().anyMatch(name -> role.getRoleName().equals(name))) + .collect(Collectors.toList()); if (roleCollList.size() != roleNameList.size()) { errorMsg.add(MsgUtils.getMessage(ErrorCodes.SYS_ROLE_ROLENAME_INEXISTENCE, excel.getRoleNameList())); @@ -338,8 +347,8 @@ public class SysUserServiceImpl extends ServiceImpl impl // 判断输入的部门名称列表是否合法 List postNameList = StrUtil.split(excel.getPostNameList(), StrUtil.COMMA); List postCollList = postList.stream() - .filter(post -> postNameList.stream().anyMatch(name -> post.getPostName().equals(name))) - .collect(Collectors.toList()); + .filter(post -> postNameList.stream().anyMatch(name -> post.getPostName().equals(name))) + .collect(Collectors.toList()); if (postCollList.size() != postNameList.size()) { errorMsg.add(MsgUtils.getMessage(ErrorCodes.SYS_POST_POSTNAME_INEXISTENCE, excel.getPostNameList())); @@ -442,8 +451,9 @@ public class SysUserServiceImpl extends ServiceImpl impl } String password = ENCODER.encode(userDto.getNewpassword1()); - this.update(Wrappers.lambdaUpdate().set(SysUser::getPassword, password).eq(SysUser::getUserId, - userVO.getUserId())); + this.update(Wrappers.lambdaUpdate() + .set(SysUser::getPassword, password) + .eq(SysUser::getUserId, userVO.getUserId())); return R.ok(); } @@ -452,20 +462,24 @@ public class SysUserServiceImpl extends ServiceImpl impl PigxUser user = SecurityUtils.getUser(); LambdaUpdateWrapper wrapper = null; if (type.equals("wechat")) { - wrapper = Wrappers.lambdaUpdate().set(SysUser::getWxOpenid, null).eq(SysUser::getUserId, - user.getId()); + wrapper = Wrappers.lambdaUpdate() + .set(SysUser::getWxOpenid, null) + .eq(SysUser::getUserId, user.getId()); } else if (type.equals("gitee")) { - wrapper = Wrappers.lambdaUpdate().set(SysUser::getGiteeLogin, null).eq(SysUser::getUserId, - user.getId()); + wrapper = Wrappers.lambdaUpdate() + .set(SysUser::getGiteeLogin, null) + .eq(SysUser::getUserId, user.getId()); } else if (type.equals("osc")) { - wrapper = Wrappers.lambdaUpdate().set(SysUser::getOscId, null).eq(SysUser::getUserId, - user.getId()); + wrapper = Wrappers.lambdaUpdate() + .set(SysUser::getOscId, null) + .eq(SysUser::getUserId, user.getId()); } else if (type.equals("tencent")) { - wrapper = Wrappers.lambdaUpdate().set(SysUser::getTenantId, null).eq(SysUser::getUserId, - user.getId()); + wrapper = Wrappers.lambdaUpdate() + .set(SysUser::getTenantId, null) + .eq(SysUser::getUserId, user.getId()); } if (wrapper == null) { return R.failed("解绑账号类型不存在"); @@ -490,4 +504,22 @@ public class SysUserServiceImpl extends ServiceImpl impl } } + @Override + public List listUserIdByRoleIds(List roleIdList) { + return sysUserRoleMapper.selectList(Wrappers.lambdaQuery().in(SysUserRole::getRoleId, roleIdList)) + .stream() + .map(SysUserRole::getRoleId) + .collect(Collectors.toList()); + } + + /** + * 根据部门ID列表获取用户ID列表接口 + * @param deptIdList 部门ID列表 + * @return List 返回结果对象,包含根据部门ID列表获取到的用户ID列表信息 + */ + @Override + public List listUserIdByDeptIds(List deptIdList) { + return baseMapper.selectList(Wrappers.lambdaQuery().in(SysUser::getDeptId, deptIdList)); + } + } diff --git a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/controller/GenDsConfController.java b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/controller/GenDsConfController.java index 137a714d1..ab2392db1 100755 --- a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/controller/GenDsConfController.java +++ b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/controller/GenDsConfController.java @@ -31,12 +31,12 @@ import com.pig4cloud.pigx.common.core.util.R; import com.pig4cloud.pigx.common.core.util.SpringContextHolder; import com.pig4cloud.pigx.common.security.annotation.Inner; import com.pig4cloud.pigx.common.xss.core.XssCleanIgnore; +import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import org.springframework.http.HttpHeaders; import org.springframework.web.bind.annotation.*; -import jakarta.servlet.http.HttpServletResponse; import javax.sql.DataSource; /** @@ -63,8 +63,9 @@ public class GenDsConfController { @GetMapping("/page") public R getSysDatasourceConfPage(Page page, GenDatasourceConf datasourceConf) { return R.ok(datasourceConfService.page(page, - Wrappers.lambdaQuery().like(StrUtil.isNotBlank(datasourceConf.getDsName()), - GenDatasourceConf::getDsName, datasourceConf.getDsName()))); + Wrappers.lambdaQuery() + .like(StrUtil.isNotBlank(datasourceConf.getDsName()), GenDatasourceConf::getDsName, + datasourceConf.getDsName()))); } /** diff --git a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/controller/GenFieldTypeController.java b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/controller/GenFieldTypeController.java index a81301f5e..6581e43dd 100644 --- a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/controller/GenFieldTypeController.java +++ b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/controller/GenFieldTypeController.java @@ -60,8 +60,9 @@ public class GenFieldTypeController { @GetMapping("/page") public R getFieldTypePage(Page page, GenFieldType fieldType) { return R.ok(fieldTypeService.page(page, - Wrappers.lambdaQuery().like(StrUtil.isNotBlank(fieldType.getColumnType()), - GenFieldType::getColumnType, fieldType.getColumnType()))); + Wrappers.lambdaQuery() + .like(StrUtil.isNotBlank(fieldType.getColumnType()), GenFieldType::getColumnType, + fieldType.getColumnType()))); } @Operation(summary = "查询列表", description = "查询列表") diff --git a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/controller/GenGroupController.java b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/controller/GenGroupController.java index 888e40790..e7b2fc24c 100644 --- a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/controller/GenGroupController.java +++ b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/controller/GenGroupController.java @@ -64,9 +64,8 @@ public class GenGroupController { @PreAuthorize("@pms.hasPermission('codegen_group_view')") public R getgenGroupPage(Page page, GenGroupEntity genGroup) { LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .like(genGroup.getId() != null, GenGroupEntity::getId, genGroup.getId()) - .like(StrUtil.isNotEmpty(genGroup.getGroupName()), GenGroupEntity::getGroupName, - genGroup.getGroupName()); + .like(genGroup.getId() != null, GenGroupEntity::getId, genGroup.getId()) + .like(StrUtil.isNotEmpty(genGroup.getGroupName()), GenGroupEntity::getGroupName, genGroup.getGroupName()); return R.ok(genGroupService.page(page, wrapper)); } diff --git a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/controller/GenTableController.java b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/controller/GenTableController.java index 4c5d79aa8..311832018 100644 --- a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/controller/GenTableController.java +++ b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/controller/GenTableController.java @@ -155,7 +155,8 @@ public class GenTableController { Wrappers.lambdaQuery().eq(GenTable::getDsName, dsName).eq(GenTable::getTableName, tableName)); // 字段配置删除 tableColumnService.remove(Wrappers.lambdaQuery() - .eq(GenTableColumnEntity::getDsName, dsName).eq(GenTableColumnEntity::getTableName, tableName)); + .eq(GenTableColumnEntity::getDsName, dsName) + .eq(GenTableColumnEntity::getTableName, tableName)); return R.ok(tableService.queryOrBuildTable(dsName, tableName)); } diff --git a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/controller/GenTemplateController.java b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/controller/GenTemplateController.java index f9e3a5003..b419c0703 100644 --- a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/controller/GenTemplateController.java +++ b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/controller/GenTemplateController.java @@ -64,9 +64,9 @@ public class GenTemplateController { @PreAuthorize("@pms.hasPermission('codegen_template_view')") public R getgenTemplatePage(Page page, GenTemplateEntity genTemplate) { LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .like(genTemplate.getId() != null, GenTemplateEntity::getId, genTemplate.getId()) - .like(StrUtil.isNotEmpty(genTemplate.getTemplateName()), GenTemplateEntity::getTemplateName, - genTemplate.getTemplateName()); + .like(genTemplate.getId() != null, GenTemplateEntity::getId, genTemplate.getId()) + .like(StrUtil.isNotEmpty(genTemplate.getTemplateName()), GenTemplateEntity::getTemplateName, + genTemplate.getTemplateName()); return R.ok(genTemplateService.page(page, wrapper)); } diff --git a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/impl/GenDatasourceConfServiceImpl.java b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/impl/GenDatasourceConfServiceImpl.java index 8beddb937..271d2298c 100755 --- a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/impl/GenDatasourceConfServiceImpl.java +++ b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/impl/GenDatasourceConfServiceImpl.java @@ -110,7 +110,7 @@ public class GenDatasourceConfServiceImpl extends ServiceImpl dynamicRoutingDataSource.removeDataSource(ds.getName())); + .forEach(ds -> dynamicRoutingDataSource.removeDataSource(ds.getName())); this.baseMapper.deleteBatchIds(CollUtil.toList(dsIds)); return Boolean.TRUE; } diff --git a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/impl/GenFormConfServiceImpl.java b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/impl/GenFormConfServiceImpl.java index 9135ef12e..6ab6a5ec4 100755 --- a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/impl/GenFormConfServiceImpl.java +++ b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/impl/GenFormConfServiceImpl.java @@ -70,7 +70,8 @@ public class GenFormConfServiceImpl extends ServiceImpl options.getInt(VFormConfigConsts.span, 24)).orElse(24); + .map(options -> options.getInt(VFormConfigConsts.span, 24)) + .orElse(24); jsonObject.set(VFormConfigConsts.span, span); diff --git a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/impl/GenGroupServiceImpl.java b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/impl/GenGroupServiceImpl.java index 2b4171d10..338edf12f 100644 --- a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/impl/GenGroupServiceImpl.java +++ b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/impl/GenGroupServiceImpl.java @@ -78,7 +78,7 @@ public class GenGroupServiceImpl extends ServiceImpllambdaQuery().in(GenTemplateGroupEntity::getGroupId, ids)); + .remove(Wrappers.lambdaQuery().in(GenTemplateGroupEntity::getGroupId, ids)); } /** diff --git a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/impl/GenTableColumnServiceImpl.java b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/impl/GenTableColumnServiceImpl.java index 8d9b49a83..73899bd1c 100644 --- a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/impl/GenTableColumnServiceImpl.java +++ b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/impl/GenTableColumnServiceImpl.java @@ -81,8 +81,9 @@ public class GenTableColumnServiceImpl extends ServiceImpl tableFieldList) { AtomicInteger sort = new AtomicInteger(); - this.updateBatchById(tableFieldList.stream().peek(field -> field.setSort(sort.getAndIncrement())) - .collect(Collectors.toList())); + this.updateBatchById(tableFieldList.stream() + .peek(field -> field.setSort(sort.getAndIncrement())) + .collect(Collectors.toList())); } } diff --git a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/impl/GenTableServiceImpl.java b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/impl/GenTableServiceImpl.java index 0687b5475..30c8d4c47 100644 --- a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/impl/GenTableServiceImpl.java +++ b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/impl/GenTableServiceImpl.java @@ -116,9 +116,10 @@ public class GenTableServiceImpl extends ServiceImpl i genTable = this.tableImport(dsName, tableName); } - List fieldList = columnService - .list(Wrappers.lambdaQuery().eq(GenTableColumnEntity::getDsName, dsName) - .eq(GenTableColumnEntity::getTableName, tableName).orderByAsc(GenTableColumnEntity::getSort)); + List fieldList = columnService.list(Wrappers.lambdaQuery() + .eq(GenTableColumnEntity::getDsName, dsName) + .eq(GenTableColumnEntity::getTableName, tableName) + .orderByAsc(GenTableColumnEntity::getSort)); genTable.setFieldList(fieldList); // 查询模板分组信息 diff --git a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/impl/GeneratorServiceImpl.java b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/impl/GeneratorServiceImpl.java index dc54e353f..1397baac3 100755 --- a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/impl/GeneratorServiceImpl.java +++ b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/impl/GeneratorServiceImpl.java @@ -37,7 +37,6 @@ import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import java.io.File; import java.util.*; import java.util.stream.Collectors; import java.util.zip.ZipEntry; @@ -185,8 +184,8 @@ public class GeneratorServiceImpl implements GeneratorService { // 获取模板信息,Lambda 表达式简化代码 GenTemplateEntity genTemplateEntity = Optional - .ofNullable(genTemplateService.getById(GeneratorStyleEnum.VFORM_JSON.getTemplateId())) - .orElseThrow(() -> new Exception("模板不存在")); + .ofNullable(genTemplateService.getById(GeneratorStyleEnum.VFORM_JSON.getTemplateId())) + .orElseThrow(() -> new Exception("模板不存在")); // 渲染模板并返回结果 return VelocityKit.renderStr(genTemplateEntity.getTemplateCode(), dataModel); @@ -217,8 +216,8 @@ public class GeneratorServiceImpl implements GeneratorService { // 获取模板信息 GenTemplateEntity genTemplateEntity = Optional - .ofNullable(genTemplateService.getById(GeneratorStyleEnum.VFORM_FORM.getTemplateId())) - .orElseThrow(() -> new Exception("模板不存在")); + .ofNullable(genTemplateService.getById(GeneratorStyleEnum.VFORM_FORM.getTemplateId())) + .orElseThrow(() -> new Exception("模板不存在")); // 渲染模板并返回结果 return VelocityKit.renderStr(genTemplateEntity.getTemplateCode(), dataModel); @@ -234,9 +233,10 @@ public class GeneratorServiceImpl implements GeneratorService { GenTable table = tableService.getById(tableId); // 获取字段列表 List fieldList = columnService.lambdaQuery() - .eq(GenTableColumnEntity::getDsName, table.getDsName()) - .eq(GenTableColumnEntity::getTableName, table.getTableName()).orderByAsc(GenTableColumnEntity::getSort) - .list(); + .eq(GenTableColumnEntity::getDsName, table.getDsName()) + .eq(GenTableColumnEntity::getTableName, table.getTableName()) + .orderByAsc(GenTableColumnEntity::getSort) + .list(); table.setFieldList(fieldList); @@ -275,8 +275,9 @@ public class GeneratorServiceImpl implements GeneratorService { String childTableName = table.getChildTableName(); if (StrUtil.isNotBlank(childTableName)) { List childFieldList = columnService.lambdaQuery() - .eq(GenTableColumnEntity::getDsName, table.getDsName()) - .eq(GenTableColumnEntity::getTableName, table.getChildTableName()).list(); + .eq(GenTableColumnEntity::getDsName, table.getDsName()) + .eq(GenTableColumnEntity::getTableName, table.getChildTableName()) + .list(); dataModel.put("childFieldList", childFieldList); dataModel.put("childTableName", childTableName); dataModel.put("mainField", NamingCase.toCamelCase(table.getMainField())); @@ -295,17 +296,24 @@ public class GeneratorServiceImpl implements GeneratorService { */ private void setFieldTypeList(Map dataModel, GenTable table) { // 按字段类型分组,使用 Map 存储不同类型的字段列表 - Map> typeMap = table.getFieldList().stream() - .collect(Collectors.partitioningBy(GenTableColumnEntity::isPrimaryPk)); + Map> typeMap = table.getFieldList() + .stream() + .collect(Collectors.partitioningBy(GenTableColumnEntity::isPrimaryPk)); // 从分组后的 Map 中获取不同类型的字段列表 List primaryList = typeMap.get(true); - List formList = typeMap.get(false).stream().filter(GenTableColumnEntity::isFormItem) - .collect(Collectors.toList()); - List gridList = typeMap.get(false).stream().filter(GenTableColumnEntity::isGridItem) - .collect(Collectors.toList()); - List queryList = typeMap.get(false).stream().filter(GenTableColumnEntity::isQueryItem) - .collect(Collectors.toList()); + List formList = typeMap.get(false) + .stream() + .filter(GenTableColumnEntity::isFormItem) + .collect(Collectors.toList()); + List gridList = typeMap.get(false) + .stream() + .filter(GenTableColumnEntity::isGridItem) + .collect(Collectors.toList()); + List queryList = typeMap.get(false) + .stream() + .filter(GenTableColumnEntity::isQueryItem) + .collect(Collectors.toList()); if (CollUtil.isNotEmpty(primaryList)) { dataModel.put("pk", primaryList.get(0)); diff --git a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/util/GenKit.java b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/util/GenKit.java index a9605ebf4..92af31dfa 100644 --- a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/util/GenKit.java +++ b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/util/GenKit.java @@ -48,7 +48,7 @@ public class GenKit { // 获取目标数据源数据库类型 GenDatasourceConfMapper datasourceConfMapper = SpringContextHolder.getBean(GenDatasourceConfMapper.class); GenDatasourceConf datasourceConf = datasourceConfMapper - .selectOne(Wrappers.lambdaQuery().eq(GenDatasourceConf::getName, dsName)); + .selectOne(Wrappers.lambdaQuery().eq(GenDatasourceConf::getName, dsName)); String dbConfType; // 默认MYSQL 数据源 diff --git a/pigx-visual/pigx-daemon-quartz/src/main/java/com/pig4cloud/pigx/daemon/quartz/config/PigxQuartzConfig.java b/pigx-visual/pigx-daemon-quartz/src/main/java/com/pig4cloud/pigx/daemon/quartz/config/PigxQuartzConfig.java index fb8a7d6ba..fab54628d 100644 --- a/pigx-visual/pigx-daemon-quartz/src/main/java/com/pig4cloud/pigx/daemon/quartz/config/PigxQuartzConfig.java +++ b/pigx-visual/pigx-daemon-quartz/src/main/java/com/pig4cloud/pigx/daemon/quartz/config/PigxQuartzConfig.java @@ -74,8 +74,8 @@ public class PigxQuartzConfig { @ConditionalOnMissingBean public SchedulerFactoryBean quartzScheduler() { SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(); - schedulerFactoryBean.setJobFactory( - new AutowireCapableBeanJobFactory(this.applicationContext.getAutowireCapableBeanFactory())); + schedulerFactoryBean + .setJobFactory(new AutowireCapableBeanJobFactory(this.applicationContext.getAutowireCapableBeanFactory())); if (!this.properties.getProperties().isEmpty()) { schedulerFactoryBean.setQuartzProperties(this.asProperties(this.properties.getProperties())); } diff --git a/pigx-visual/pigx-daemon-quartz/src/main/java/com/pig4cloud/pigx/daemon/quartz/config/PigxQuartzFactory.java b/pigx-visual/pigx-daemon-quartz/src/main/java/com/pig4cloud/pigx/daemon/quartz/config/PigxQuartzFactory.java index 333eb6ba0..4275218d8 100644 --- a/pigx-visual/pigx-daemon-quartz/src/main/java/com/pig4cloud/pigx/daemon/quartz/config/PigxQuartzFactory.java +++ b/pigx-visual/pigx-daemon-quartz/src/main/java/com/pig4cloud/pigx/daemon/quartz/config/PigxQuartzFactory.java @@ -43,7 +43,7 @@ public class PigxQuartzFactory implements Job { @SneakyThrows public void execute(JobExecutionContext jobExecutionContext) { SysJob sysJob = (SysJob) jobExecutionContext.getMergedJobDataMap() - .get(PigxQuartzEnum.SCHEDULE_JOB_KEY.getType()); + .get(PigxQuartzEnum.SCHEDULE_JOB_KEY.getType()); pigxQuartzInvokeFactory.init(sysJob, jobExecutionContext.getTrigger()); } diff --git a/pigx-visual/pigx-daemon-quartz/src/main/java/com/pig4cloud/pigx/daemon/quartz/controller/SysJobController.java b/pigx-visual/pigx-daemon-quartz/src/main/java/com/pig4cloud/pigx/daemon/quartz/controller/SysJobController.java index cb1e4cd52..13a4acfb8 100644 --- a/pigx-visual/pigx-daemon-quartz/src/main/java/com/pig4cloud/pigx/daemon/quartz/controller/SysJobController.java +++ b/pigx-visual/pigx-daemon-quartz/src/main/java/com/pig4cloud/pigx/daemon/quartz/controller/SysJobController.java @@ -74,11 +74,11 @@ public class SysJobController { @Operation(description = "分页定时业务查询") public R getSysJobPage(Page page, SysJob sysJob) { LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .like(StrUtil.isNotBlank(sysJob.getJobName()), SysJob::getJobName, sysJob.getJobName()) - .like(StrUtil.isNotBlank(sysJob.getJobGroup()), SysJob::getJobGroup, sysJob.getJobGroup()) - .eq(StrUtil.isNotBlank(sysJob.getJobStatus()), SysJob::getJobStatus, sysJob.getJobGroup()) - .eq(StrUtil.isNotBlank(sysJob.getJobExecuteStatus()), SysJob::getJobExecuteStatus, - sysJob.getJobExecuteStatus()); + .like(StrUtil.isNotBlank(sysJob.getJobName()), SysJob::getJobName, sysJob.getJobName()) + .like(StrUtil.isNotBlank(sysJob.getJobGroup()), SysJob::getJobGroup, sysJob.getJobGroup()) + .eq(StrUtil.isNotBlank(sysJob.getJobStatus()), SysJob::getJobStatus, sysJob.getJobGroup()) + .eq(StrUtil.isNotBlank(sysJob.getJobExecuteStatus()), SysJob::getJobExecuteStatus, + sysJob.getJobExecuteStatus()); return R.ok(sysJobService.page(page, wrapper)); } @@ -170,8 +170,8 @@ public class SysJobController { // 更新定时任务状态条件,运行状态2更新为暂停状态2 this.sysJobService.update( SysJob.builder().jobStatus(PigxQuartzEnum.JOB_STATUS_NOT_RUNNING.getType()).build(), - new UpdateWrapper().lambda().eq(SysJob::getJobStatus, - PigxQuartzEnum.JOB_STATUS_RUNNING.getType())); + new UpdateWrapper().lambda() + .eq(SysJob::getJobStatus, PigxQuartzEnum.JOB_STATUS_RUNNING.getType())); return R.ok("暂停成功"); } } @@ -187,8 +187,8 @@ public class SysJobController { public R startJobs() { // 更新定时任务状态条件,暂停状态3更新为运行状态2 this.sysJobService.update(SysJob.builder().jobStatus(PigxQuartzEnum.JOB_STATUS_RUNNING.getType()).build(), - new UpdateWrapper().lambda().eq(SysJob::getJobStatus, - PigxQuartzEnum.JOB_STATUS_NOT_RUNNING.getType())); + new UpdateWrapper().lambda() + .eq(SysJob::getJobStatus, PigxQuartzEnum.JOB_STATUS_NOT_RUNNING.getType())); taskUtil.startJobs(scheduler); return R.ok(); } @@ -236,8 +236,8 @@ public class SysJobController { taskUtil.resumeJob(querySysJob, scheduler); } // 更新定时任务状态条件,暂停状态3更新为运行状态2 - this.sysJobService.updateById( - SysJob.builder().jobId(jobId).jobStatus(PigxQuartzEnum.JOB_STATUS_RUNNING.getType()).build()); + this.sysJobService + .updateById(SysJob.builder().jobId(jobId).jobStatus(PigxQuartzEnum.JOB_STATUS_RUNNING.getType()).build()); return R.ok(); } @@ -266,8 +266,10 @@ public class SysJobController { public R shutdownJob(@PathVariable("id") Long id) { SysJob querySysJob = this.sysJobService.getById(id); // 更新定时任务状态条件,运行状态2更新为暂停状态3 - this.sysJobService.updateById(SysJob.builder().jobId(querySysJob.getJobId()) - .jobStatus(PigxQuartzEnum.JOB_STATUS_NOT_RUNNING.getType()).build()); + this.sysJobService.updateById(SysJob.builder() + .jobId(querySysJob.getJobId()) + .jobStatus(PigxQuartzEnum.JOB_STATUS_NOT_RUNNING.getType()) + .build()); taskUtil.pauseJob(querySysJob, scheduler); return R.ok(); } @@ -290,8 +292,8 @@ public class SysJobController { @Operation(description = "检验任务名称和任务组联合是否唯一") public R isValidTaskName(@RequestParam String jobName, @RequestParam String jobGroup) { return this.sysJobService - .count(Wrappers.query(SysJob.builder().jobName(jobName).jobGroup(jobGroup).build())) > 0 - ? R.failed("任务重复,请检查此组内是否已包含同名任务") : R.ok(); + .count(Wrappers.query(SysJob.builder().jobName(jobName).jobGroup(jobGroup).build())) > 0 + ? R.failed("任务重复,请检查此组内是否已包含同名任务") : R.ok(); } /** diff --git a/pigx-visual/pigx-daemon-quartz/src/main/java/com/pig4cloud/pigx/daemon/quartz/util/TaskInvokUtil.java b/pigx-visual/pigx-daemon-quartz/src/main/java/com/pig4cloud/pigx/daemon/quartz/util/TaskInvokUtil.java index 8ef57f4b4..92b752bbb 100644 --- a/pigx-visual/pigx-daemon-quartz/src/main/java/com/pig4cloud/pigx/daemon/quartz/util/TaskInvokUtil.java +++ b/pigx-visual/pigx-daemon-quartz/src/main/java/com/pig4cloud/pigx/daemon/quartz/util/TaskInvokUtil.java @@ -99,8 +99,8 @@ public class TaskInvokUtil { finally { // 记录执行时间 立刻执行使用的是simpleTeigger if (trigger instanceof CronTrigger) { - updateSysjob.setStartTime( - trigger.getStartTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()); + updateSysjob + .setStartTime(trigger.getStartTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()); updateSysjob.setPreviousTime( trigger.getPreviousFireTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()); updateSysjob.setNextTime( diff --git a/pigx-visual/pigx-daemon-quartz/src/main/java/com/pig4cloud/pigx/daemon/quartz/util/TaskUtil.java b/pigx-visual/pigx-daemon-quartz/src/main/java/com/pig4cloud/pigx/daemon/quartz/util/TaskUtil.java index 0b234b8d2..e93ae30e9 100644 --- a/pigx-visual/pigx-daemon-quartz/src/main/java/com/pig4cloud/pigx/daemon/quartz/util/TaskUtil.java +++ b/pigx-visual/pigx-daemon-quartz/src/main/java/com/pig4cloud/pigx/daemon/quartz/util/TaskUtil.java @@ -73,8 +73,10 @@ public class TaskUtil { CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(sysjob.getCronExpression()); cronScheduleBuilder = this.handleCronScheduleMisfirePolicy(sysjob, cronScheduleBuilder); // 创建触发器并将cron表达式对象给塞入 - trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder) - .build(); + trigger = TriggerBuilder.newTrigger() + .withIdentity(triggerKey) + .withSchedule(cronScheduleBuilder) + .build(); // 在调度器中将触发器和任务进行组合 scheduler.scheduleJob(jobDetail, trigger); } @@ -82,8 +84,10 @@ public class TaskUtil { CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(sysjob.getCronExpression()); cronScheduleBuilder = this.handleCronScheduleMisfirePolicy(sysjob, cronScheduleBuilder); // 按照新的规则进行 - trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(cronScheduleBuilder) - .build(); + trigger = trigger.getTriggerBuilder() + .withIdentity(triggerKey) + .withSchedule(cronScheduleBuilder) + .build(); // 将任务信息更新到任务信息中 trigger.getJobDataMap().put(PigxQuartzEnum.SCHEDULE_JOB_KEY.getType(), sysjob); // 重启 diff --git a/pigx-visual/pigx-monitor/src/main/java/com/pig4cloud/pigx/monitor/model/dto/WallResult.java b/pigx-visual/pigx-monitor/src/main/java/com/pig4cloud/pigx/monitor/model/dto/WallResult.java index be6f81183..c449c2403 100755 --- a/pigx-visual/pigx-monitor/src/main/java/com/pig4cloud/pigx/monitor/model/dto/WallResult.java +++ b/pigx-visual/pigx-monitor/src/main/java/com/pig4cloud/pigx/monitor/model/dto/WallResult.java @@ -122,32 +122,46 @@ public class WallResult { */ public void sum(WallResult wallResult, WallResult sumResult) { sumResult.getContent() - .setCheckCount(sumResult.getContent().getCheckCount() + wallResult.getContent().getCheckCount()); - sumResult.getContent().setHardCheckCount( - sumResult.getContent().getHardCheckCount() + wallResult.getContent().getHardCheckCount()); - sumResult.getContent().setViolationCount( - sumResult.getContent().getViolationCount() + wallResult.getContent().getViolationCount()); - sumResult.getContent().setViolationEffectRowCount(sumResult.getContent().getViolationEffectRowCount() - + wallResult.getContent().getViolationEffectRowCount()); - sumResult.getContent().setBlackListHitCount( - sumResult.getContent().getBlackListHitCount() + wallResult.getContent().getBlackListHitCount()); - sumResult.getContent().setBlackListSize( - sumResult.getContent().getBlackListSize() + wallResult.getContent().getBlackListSize()); - sumResult.getContent().setWhiteListHitCount( - sumResult.getContent().getWhiteListHitCount() + wallResult.getContent().getWhiteListHitCount()); - sumResult.getContent().setWhiteListSize( - sumResult.getContent().getWhiteListSize() + wallResult.getContent().getWhiteListSize()); - sumResult.getContent().setSyntaxErrorCount( - sumResult.getContent().getSyntaxErrorCount() + wallResult.getContent().getSyntaxErrorCount()); + .setCheckCount(sumResult.getContent().getCheckCount() + wallResult.getContent().getCheckCount()); + sumResult.getContent() + .setHardCheckCount( + sumResult.getContent().getHardCheckCount() + wallResult.getContent().getHardCheckCount()); + sumResult.getContent() + .setViolationCount( + sumResult.getContent().getViolationCount() + wallResult.getContent().getViolationCount()); + sumResult.getContent() + .setViolationEffectRowCount(sumResult.getContent().getViolationEffectRowCount() + + wallResult.getContent().getViolationEffectRowCount()); + sumResult.getContent() + .setBlackListHitCount( + sumResult.getContent().getBlackListHitCount() + wallResult.getContent().getBlackListHitCount()); + sumResult.getContent() + .setBlackListSize(sumResult.getContent().getBlackListSize() + wallResult.getContent().getBlackListSize()); + sumResult.getContent() + .setWhiteListHitCount( + sumResult.getContent().getWhiteListHitCount() + wallResult.getContent().getWhiteListHitCount()); + sumResult.getContent() + .setWhiteListSize(sumResult.getContent().getWhiteListSize() + wallResult.getContent().getWhiteListSize()); + sumResult.getContent() + .setSyntaxErrorCount( + sumResult.getContent().getSyntaxErrorCount() + wallResult.getContent().getSyntaxErrorCount()); - sumResult.getContent().getTables().addAll(wallResult.getContent().getTables() == null ? Collections.emptyList() - : wallResult.getContent().getTables()); - sumResult.getContent().getFunctions().addAll(wallResult.getContent().getFunctions() == null - ? Collections.emptyList() : wallResult.getContent().getFunctions()); - sumResult.getContent().getBlackList().addAll(wallResult.getContent().getBlackList() == null - ? Collections.emptyList() : wallResult.getContent().getBlackList()); - sumResult.getContent().getWhiteList().addAll(wallResult.getContent().getWhiteList() == null - ? Collections.emptyList() : wallResult.getContent().getWhiteList()); + sumResult.getContent() + .getTables() + .addAll(wallResult.getContent().getTables() == null ? Collections.emptyList() + : wallResult.getContent().getTables()); + sumResult.getContent() + .getFunctions() + .addAll(wallResult.getContent().getFunctions() == null ? Collections.emptyList() + : wallResult.getContent().getFunctions()); + sumResult.getContent() + .getBlackList() + .addAll(wallResult.getContent().getBlackList() == null ? Collections.emptyList() + : wallResult.getContent().getBlackList()); + sumResult.getContent() + .getWhiteList() + .addAll(wallResult.getContent().getWhiteList() == null ? Collections.emptyList() + : wallResult.getContent().getWhiteList()); } } diff --git a/pigx-visual/pigx-monitor/src/main/java/com/pig4cloud/pigx/monitor/service/impl/MonitorStatService.java b/pigx-visual/pigx-monitor/src/main/java/com/pig4cloud/pigx/monitor/service/impl/MonitorStatService.java index fbcba00b2..bde1e7aad 100755 --- a/pigx-visual/pigx-monitor/src/main/java/com/pig4cloud/pigx/monitor/service/impl/MonitorStatService.java +++ b/pigx-visual/pigx-monitor/src/main/java/com/pig4cloud/pigx/monitor/service/impl/MonitorStatService.java @@ -87,8 +87,8 @@ public class MonitorStatService implements DruidStatServiceMBean { } } return serviceNodes.parallelStream() - .collect(Collectors.toMap(i -> i.getServiceName() + "-" + i.getAddress() + "-" + i.getPort(), - Function.identity(), (v1, v2) -> v2)); + .collect(Collectors.toMap(i -> i.getServiceName() + "-" + i.getAddress() + "-" + i.getPort(), + Function.identity(), (v1, v2) -> v2)); } /** @@ -121,8 +121,8 @@ public class MonitorStatService implements DruidStatServiceMBean { } } return serviceNodes.parallelStream() - .collect(Collectors.toMap(i -> i.getServiceName() + "-" + i.getAddress() + "-" + i.getPort(), - Function.identity(), (v1, v2) -> v2)); + .collect(Collectors.toMap(i -> i.getServiceName() + "-" + i.getAddress() + "-" + i.getPort(), + Function.identity(), (v1, v2) -> v2)); } @Override diff --git a/pigx-visual/pigx-monitor/src/main/java/com/pig4cloud/pigx/monitor/service/impl/RedisServiceImpl.java b/pigx-visual/pigx-monitor/src/main/java/com/pig4cloud/pigx/monitor/service/impl/RedisServiceImpl.java index 22df8e8db..02cb65deb 100644 --- a/pigx-visual/pigx-monitor/src/main/java/com/pig4cloud/pigx/monitor/service/impl/RedisServiceImpl.java +++ b/pigx-visual/pigx-monitor/src/main/java/com/pig4cloud/pigx/monitor/service/impl/RedisServiceImpl.java @@ -31,7 +31,7 @@ public class RedisServiceImpl implements RedisService { public Map getInfo() { Properties info = (Properties) redisTemplate.execute((RedisCallback) redisConnection -> redisConnection.info()); Properties commandStats = (Properties) redisTemplate - .execute((RedisCallback) redisConnection -> redisConnection.info("commandstats")); + .execute((RedisCallback) redisConnection -> redisConnection.info("commandstats")); Object dbSize = redisTemplate.execute((RedisCallback) redisConnection -> redisConnection.dbSize()); Map result = new HashMap<>(4); diff --git a/pigx-visual/pigx-monitor/src/main/java/com/pig4cloud/pigx/monitor/support/MonitorViewServlet.java b/pigx-visual/pigx-monitor/src/main/java/com/pig4cloud/pigx/monitor/support/MonitorViewServlet.java index ca208402d..c304e3be9 100755 --- a/pigx-visual/pigx-monitor/src/main/java/com/pig4cloud/pigx/monitor/support/MonitorViewServlet.java +++ b/pigx-visual/pigx-monitor/src/main/java/com/pig4cloud/pigx/monitor/support/MonitorViewServlet.java @@ -6,7 +6,6 @@ import com.pig4cloud.pigx.monitor.service.impl.MonitorStatService; import jakarta.servlet.ServletException; import lombok.extern.slf4j.Slf4j; - /** * @author linchtech * @date 2020-09-16 11:10 diff --git a/pigx-visual/pigx-monitor/src/main/java/com/pig4cloud/pigx/monitor/support/NacosServiceInstanceConverter.java b/pigx-visual/pigx-monitor/src/main/java/com/pig4cloud/pigx/monitor/support/NacosServiceInstanceConverter.java index 91579715a..decc3a659 100644 --- a/pigx-visual/pigx-monitor/src/main/java/com/pig4cloud/pigx/monitor/support/NacosServiceInstanceConverter.java +++ b/pigx-visual/pigx-monitor/src/main/java/com/pig4cloud/pigx/monitor/support/NacosServiceInstanceConverter.java @@ -20,10 +20,11 @@ public class NacosServiceInstanceConverter extends DefaultServiceInstanceConvert @Override protected Map getMetadata(ServiceInstance instance) { - return (instance.getMetadata() != null) - ? instance.getMetadata().entrySet().stream().filter((e) -> e.getKey() != null && e.getValue() != null) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)) - : emptyMap(); + return (instance.getMetadata() != null) ? instance.getMetadata() + .entrySet() + .stream() + .filter((e) -> e.getKey() != null && e.getValue() != null) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)) : emptyMap(); } } diff --git a/pigx-visual/pigx-report-platform/src/main/java/com/pig4cloud/pigx/report/config/SecurityRequestFilter.java b/pigx-visual/pigx-report-platform/src/main/java/com/pig4cloud/pigx/report/config/SecurityRequestFilter.java index 3a576bf81..e21c27754 100644 --- a/pigx-visual/pigx-report-platform/src/main/java/com/pig4cloud/pigx/report/config/SecurityRequestFilter.java +++ b/pigx-visual/pigx-report-platform/src/main/java/com/pig4cloud/pigx/report/config/SecurityRequestFilter.java @@ -79,8 +79,9 @@ public class SecurityRequestFilter extends OncePerRequestFilter { // 获取用户信息 Optional principalName = RetOps - .of(remoteTokenService.queryToken(accessToken, tenantId, SecurityConstants.FROM_IN)) - .getDataIf(RetOps.CODE_SUCCESS).map(o -> (String) o.get("principalName")); + .of(remoteTokenService.queryToken(accessToken, tenantId, SecurityConstants.FROM_IN)) + .getDataIf(RetOps.CODE_SUCCESS) + .map(o -> (String) o.get("principalName")); // 如果用户信息不存在,返回错误信息 if (!principalName.isPresent()) { diff --git a/pom.xml b/pom.xml index d5ea51364..76ac85ae4 100644 --- a/pom.xml +++ b/pom.xml @@ -33,19 +33,20 @@ - 3.1.1 + 3.1.2 2022.0.3 2022.0.0.0-RC2 UTF-8 17 17 - 3.1.1 + 3.1.2 1.1.1 3.8.1 0.0.39 2.2.5 1.3.0 3.6.4 + 7.0.0.M1 2.0.0 3.0.0 2.0.9 @@ -118,6 +119,7 @@ pigx-auth pigx-upms pigx-common + pigx-flow pigx-visual pigx-app-server