diff --git a/ruoyi-extend/pom.xml b/ruoyi-extend/pom.xml
index ee176e998..d6966e120 100644
--- a/ruoyi-extend/pom.xml
+++ b/ruoyi-extend/pom.xml
@@ -14,6 +14,7 @@
ruoyi-monitor-admin
ruoyi-xxl-job-admin
+ ruoyi-flow-ui
diff --git a/ruoyi-extend/ruoyi-flow-ui/.gitignore b/ruoyi-extend/ruoyi-flow-ui/.gitignore
new file mode 100644
index 000000000..549e00a2a
--- /dev/null
+++ b/ruoyi-extend/ruoyi-flow-ui/.gitignore
@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/ruoyi-extend/ruoyi-flow-ui/Dockerfile b/ruoyi-extend/ruoyi-flow-ui/Dockerfile
new file mode 100644
index 000000000..448cda7e6
--- /dev/null
+++ b/ruoyi-extend/ruoyi-flow-ui/Dockerfile
@@ -0,0 +1,16 @@
+FROM anapsix/alpine-java:8_server-jre_unlimited
+
+MAINTAINER zmx
+
+RUN mkdir -p /ruoyi/flow/ui/logs
+
+WORKDIR /ruoyi/flow/ui
+
+ENV TZ=PRC
+RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
+
+EXPOSE 9205
+
+ADD ./target/ruoyi-flow-ui.jar ./app.jar
+
+ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"]
diff --git a/ruoyi-extend/ruoyi-flow-ui/HELP.md b/ruoyi-extend/ruoyi-flow-ui/HELP.md
new file mode 100644
index 000000000..5265b3d40
--- /dev/null
+++ b/ruoyi-extend/ruoyi-flow-ui/HELP.md
@@ -0,0 +1,10 @@
+# Getting Started
+
+### Reference Documentation
+
+For further reference, please consider the following sections:
+
+* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html)
+* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/3.1.0/maven-plugin/reference/html/)
+* [Create an OCI image](https://docs.spring.io/spring-boot/docs/3.1.0/maven-plugin/reference/html/#build-image)
+
diff --git a/ruoyi-extend/ruoyi-flow-ui/pom.xml b/ruoyi-extend/ruoyi-flow-ui/pom.xml
new file mode 100644
index 000000000..1592a2bc6
--- /dev/null
+++ b/ruoyi-extend/ruoyi-flow-ui/pom.xml
@@ -0,0 +1,137 @@
+
+
+ 4.0.0
+
+ ruoyi-extend
+ org.dromara
+ ${revision}
+
+ ruoyi-flow-ui
+ ruoyi-flow-ui
+ ruoyi-flow-ui
+
+ 2.7.12
+ 2.7.10
+ 2.2.2
+ 6.8.0
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ ${spring-boot.version}
+ pom
+ import
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jdbc
+
+
+
+
+ com.mysql
+ mysql-connector-j
+
+
+
+ org.flowable
+ flowable-spring-boot-starter
+ ${flowable.version}
+
+
+
+ org.flowable
+ flowable-spring-boot-starter-ui-idm
+ ${flowable.version}
+
+
+
+ org.flowable
+ flowable-spring-boot-starter-ui-modeler
+ ${flowable.version}
+
+
+
+ cn.hutool
+ hutool-all
+ ${hutool.version}
+
+
+
+ commons-collections
+ commons-collections
+ 3.2.2
+
+
+
+
+ org.flowable
+ flowable-spring-boot-starter-ui-task
+ ${flowable.version}
+
+
+
+ org.flowable
+ flowable-spring-boot-starter-ui-admin
+ ${flowable.version}
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+
+
+ de.codecentric
+ spring-boot-admin-starter-client
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+ ${project.artifactId}
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring-boot.version}
+
+
+
+ repackage
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-extend/ruoyi-flow-ui/src/main/java/com/dromara/flow/ui/FlowUiApplication.java b/ruoyi-extend/ruoyi-flow-ui/src/main/java/com/dromara/flow/ui/FlowUiApplication.java
new file mode 100644
index 000000000..043ca78fc
--- /dev/null
+++ b/ruoyi-extend/ruoyi-flow-ui/src/main/java/com/dromara/flow/ui/FlowUiApplication.java
@@ -0,0 +1,17 @@
+package com.dromara.flow.ui;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * flowable-ui启动类
+ * Author: 土豆仙
+ */
+@SpringBootApplication
+public class FlowUiApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(com.dromara.flow.ui.FlowUiApplication.class, args);
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-flow-ui/src/main/java/com/dromara/flow/ui/config/FlowableIdmConfig.java b/ruoyi-extend/ruoyi-flow-ui/src/main/java/com/dromara/flow/ui/config/FlowableIdmConfig.java
new file mode 100644
index 000000000..a05178b7d
--- /dev/null
+++ b/ruoyi-extend/ruoyi-flow-ui/src/main/java/com/dromara/flow/ui/config/FlowableIdmConfig.java
@@ -0,0 +1,83 @@
+package com.dromara.flow.ui.config;
+
+
+import com.dromara.flow.ui.config.idm.CustomGroupDataManager;
+import com.dromara.flow.ui.config.idm.CustomPasswordEncoder;
+import com.dromara.flow.ui.config.idm.CustomUserDataManager;
+import org.flowable.idm.engine.impl.persistence.entity.GroupEntityManager;
+import org.flowable.idm.engine.impl.persistence.entity.GroupEntityManagerImpl;
+import org.flowable.idm.engine.impl.persistence.entity.UserEntityManager;
+import org.flowable.idm.engine.impl.persistence.entity.UserEntityManagerImpl;
+import org.flowable.idm.spring.SpringIdmEngineConfiguration;
+import org.flowable.spring.boot.EngineConfigurationConfigurer;
+import org.flowable.spring.boot.idm.FlowableIdmProperties;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.crypto.password.PasswordEncoder;
+
+/**
+ * @Author: 土豆仙
+ * @Date: 2021/9/28 19:30
+ * @Description: 一旦使用视图效率不高,在这注入覆写类
+ */
+@Configuration
+public class FlowableIdmConfig implements EngineConfigurationConfigurer {
+
+ @Autowired
+ private CustomUserDataManager customUserDataManager;
+
+ @Autowired
+ private CustomGroupDataManager customGroupDataManager;
+
+ @Override
+ public void configure(SpringIdmEngineConfiguration configuration) {
+
+ //密码加密器和自建用户体系保持一致
+ CustomPasswordEncoder bc = new CustomPasswordEncoder();
+ configuration.setPasswordEncoder(bc);
+
+ //用户
+ configuration.setUserDataManager(customUserDataManager);
+ UserEntityManager userEntityManager = configuration.getUserEntityManager();
+ if (userEntityManager != null) {
+ UserEntityManagerImpl userEntityManagerImpl = new UserEntityManagerImpl(configuration, customUserDataManager);
+ configuration.setUserEntityManager(userEntityManagerImpl);
+ }
+
+ //用户-组关系
+ /*configuration.setMembershipDataManager(customMembershipDataManager);
+ configuration.setMembershipEntityManager(customMembershipEntityManager);*/
+
+
+ //组
+ configuration.setGroupDataManager(customGroupDataManager);
+ GroupEntityManager groupEntityManager = configuration.getGroupEntityManager();
+ if (groupEntityManager == null) {
+ GroupEntityManagerImpl groupEntityManagerImpl = new GroupEntityManagerImpl(configuration, customGroupDataManager);
+ configuration.setGroupEntityManager(groupEntityManagerImpl);
+ }
+
+
+ }
+
+
+ @Bean
+ public PasswordEncoder passwordEncoder(FlowableIdmProperties idmProperties) {
+
+ PasswordEncoder encoder = new CustomPasswordEncoder();
+
+ return encoder;
+ }
+
+ /* @Bean
+ public CustomGroupEntityManager customGroupEntityManager(IdmEngineConfiguration configuration) {
+ return new CustomGroupEntityManager(configuration, configuration.getGroupDataManager());
+ }*/
+
+
+ /* @Bean
+ public CustomUserEntityManager customUserEntityManager(IdmEngineConfiguration configuration) {
+ return new CustomUserEntityManager(configuration, new CustomUserDataManager(configuration));
+ }*/
+}
diff --git a/ruoyi-extend/ruoyi-flow-ui/src/main/java/com/dromara/flow/ui/config/idm/CustomGroupDataManager.java b/ruoyi-extend/ruoyi-flow-ui/src/main/java/com/dromara/flow/ui/config/idm/CustomGroupDataManager.java
new file mode 100644
index 000000000..bff43b28d
--- /dev/null
+++ b/ruoyi-extend/ruoyi-flow-ui/src/main/java/com/dromara/flow/ui/config/idm/CustomGroupDataManager.java
@@ -0,0 +1,165 @@
+package com.dromara.flow.ui.config.idm;
+
+
+import com.dromara.flow.ui.domain.bo.GroupCodeBo;
+import com.dromara.flow.ui.domain.bo.GroupNameBo;
+import com.dromara.flow.ui.domain.bo.GroupQueryBo;
+import com.dromara.flow.ui.mapper.CustomMybatisMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.flowable.engine.ManagementService;
+import org.flowable.engine.impl.cmd.AbstractCustomSqlExecution;
+import org.flowable.idm.api.Group;
+import org.flowable.idm.engine.IdmEngineConfiguration;
+import org.flowable.idm.engine.impl.GroupQueryImpl;
+import org.flowable.idm.engine.impl.persistence.entity.GroupEntity;
+import org.flowable.idm.engine.impl.persistence.entity.GroupEntityImpl;
+import org.flowable.idm.engine.impl.persistence.entity.data.AbstractIdmDataManager;
+import org.flowable.idm.engine.impl.persistence.entity.data.GroupDataManager;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+
+/**
+ * @Author: 土豆仙
+ * @Date: 2021/11/12 10:05
+ * @Description: 覆写组查询
+ */
+@Slf4j
+@Component
+public class CustomGroupDataManager extends AbstractIdmDataManager implements GroupDataManager {
+
+
+ public CustomGroupDataManager(IdmEngineConfiguration idmEngineConfiguration) {
+ super(idmEngineConfiguration);
+ }
+
+ @Autowired
+ @Lazy
+ private ManagementService managementService;
+
+ @Override
+ public Class extends GroupEntity> getManagedEntityClass() {
+ return GroupEntityImpl.class;
+ }
+
+ @Override
+ public GroupEntity create() {
+ return new GroupEntityImpl();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public List findGroupByQueryCriteria(GroupQueryImpl query) {
+ if (log.isDebugEnabled()) {
+ log.debug("已重写自定义组查询:findGroupByQueryCriteria");
+ }
+ boolean isReturnList = true;
+ GroupQueryBo groupQueryBo = transformQueryParamToGroupDTO(query);
+ if (StringUtils.isNotBlank(query.getId())) {
+ groupQueryBo.setReturnList(false);
+ isReturnList = false;
+ }
+
+ List groups = managementService.executeCustomSql(new AbstractCustomSqlExecution>(CustomMybatisMapper.class) {
+ @Override
+ public List execute(CustomMybatisMapper customMybatisMapper) {
+ return customMybatisMapper.findGroupList(groupQueryBo);
+ }
+ });
+
+ return groups;
+ //return getDbSqlSession().selectList("selectGroupByQueryCriteria", query, getManagedEntityClass());
+ }
+
+ private GroupQueryBo transformQueryParamToGroupDTO(GroupQueryImpl query) {
+ GroupQueryBo groupQueryBo = new GroupQueryBo();
+ //约定 groupId 解析为 部门code.角色code
+ List groupIds = new ArrayList<>();
+ if (StringUtils.isNotEmpty(query.getId())) {
+ groupIds.add(query.getId());
+ }
+ if (CollectionUtils.isNotEmpty(query.getIds())) {
+ groupIds.addAll(query.getIds());
+ }
+ List groupBoList = groupIds.stream()
+ .map(GroupCodeBo::new)
+ .collect(Collectors.toList());
+
+ groupQueryBo.setGroupCodeBos(groupBoList);
+
+ //约定 groupName 解析为 区域name/部门name/角色name
+ groupQueryBo.setGroupNameBo(new GroupNameBo(query.getName()));
+
+
+ //userId
+ List userNames = new ArrayList<>();
+ if (StringUtils.isNotEmpty(query.getUserId())) {
+ userNames.add(query.getUserId());
+ }
+
+ if (CollectionUtils.isNotEmpty(query.getIds())) {
+ userNames.addAll(query.getIds());
+ }
+
+ groupQueryBo.setUserNames(userNames);
+
+ return groupQueryBo;
+ }
+
+ @Override
+ public long findGroupCountByQueryCriteria(GroupQueryImpl query) {
+ if (log.isDebugEnabled()) {
+ log.debug("已重写自定义组查询:findGroupCountByQueryCriteria");
+ }
+ //return (Long) getDbSqlSession().selectOne("selectGroupCountByQueryCriteria", query);
+ List groupByQueryCriteria = findGroupByQueryCriteria(query);
+ return groupByQueryCriteria.size();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public List findGroupsByUser(String userId) {
+ if (log.isDebugEnabled()) {
+ log.debug("已重写自定义组查询:findGroupsByUser");
+ }
+ GroupQueryImpl groupQuery = new GroupQueryImpl();
+ groupQuery.groupMember(userId);
+ List groupByQueryCriteria = findGroupByQueryCriteria(groupQuery);
+ return groupByQueryCriteria;
+ //return getDbSqlSession().selectList("selectGroupsByUserId", userId);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public List findGroupsByPrivilegeId(String privilegeId) {
+ if (log.isDebugEnabled()) {
+ log.debug("未重写自定义组查询:findGroupsByPrivilegeId");
+ }
+ return getDbSqlSession().selectList("selectGroupsWithPrivilegeId", privilegeId);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public List findGroupsByNativeQuery(Map parameterMap) {
+ if (log.isDebugEnabled()) {
+ log.debug("未重写自定义组查询:findGroupsByNativeQuery");
+ }
+ return getDbSqlSession().selectListWithRawParameter("selectGroupByNativeQuery", parameterMap);
+ }
+
+ @Override
+ public long findGroupCountByNativeQuery(Map parameterMap) {
+ if (log.isDebugEnabled()) {
+ log.debug("未重写自定义组查询:findGroupCountByNativeQuery");
+ }
+ return (Long) getDbSqlSession().selectOne("selectGroupCountByNativeQuery", parameterMap);
+ }
+}
diff --git a/ruoyi-extend/ruoyi-flow-ui/src/main/java/com/dromara/flow/ui/config/idm/CustomPasswordEncoder.java b/ruoyi-extend/ruoyi-flow-ui/src/main/java/com/dromara/flow/ui/config/idm/CustomPasswordEncoder.java
new file mode 100644
index 000000000..477ee8058
--- /dev/null
+++ b/ruoyi-extend/ruoyi-flow-ui/src/main/java/com/dromara/flow/ui/config/idm/CustomPasswordEncoder.java
@@ -0,0 +1,50 @@
+package com.dromara.flow.ui.config.idm;
+
+import org.flowable.idm.api.PasswordEncoder;
+import org.flowable.idm.api.PasswordSalt;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+
+/**
+* @Author: 土豆仙
+* @Date: 2021/11/12 10:04
+* @Description: 密码加密器
+*/
+public class CustomPasswordEncoder implements PasswordEncoder,org.springframework.security.crypto.password.PasswordEncoder {
+ @Override
+ public String encode(CharSequence rawPassword, PasswordSalt passwordSalt) {
+ BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
+ return passwordEncoder.encode(rawPassword);
+ }
+
+ /**
+ * 判断密码是否相同
+ *
+ * @param rawPassword 真实密码
+ * @param encodedPassword 加密后字符
+ * @return 结果
+ */
+ @Override
+ public boolean isMatches(CharSequence rawPassword, String encodedPassword, PasswordSalt salt) {
+ /* BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();*/
+ return true;
+ }
+
+
+ @Override
+ public String encode(CharSequence rawPassword) {
+ BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
+ return passwordEncoder.encode(rawPassword);
+ }
+
+ @Override
+ public boolean matches(CharSequence rawPassword, String encodedPassword) {
+ /*BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();*/
+ return true;
+ }
+
+ @Override
+ public boolean upgradeEncoding(String encodedPassword) {
+ BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
+ return passwordEncoder.upgradeEncoding(encodedPassword);
+ }
+}
diff --git a/ruoyi-extend/ruoyi-flow-ui/src/main/java/com/dromara/flow/ui/config/idm/CustomUserDataManager.java b/ruoyi-extend/ruoyi-flow-ui/src/main/java/com/dromara/flow/ui/config/idm/CustomUserDataManager.java
new file mode 100644
index 000000000..3d9d3126e
--- /dev/null
+++ b/ruoyi-extend/ruoyi-flow-ui/src/main/java/com/dromara/flow/ui/config/idm/CustomUserDataManager.java
@@ -0,0 +1,154 @@
+package com.dromara.flow.ui.config.idm;
+
+
+import com.dromara.flow.ui.domain.bo.GroupCodeBo;
+import com.dromara.flow.ui.domain.bo.UserQueryBo;
+import com.dromara.flow.ui.mapper.CustomMybatisMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.flowable.engine.ManagementService;
+import org.flowable.engine.impl.cmd.AbstractCustomSqlExecution;
+import org.flowable.idm.api.User;
+import org.flowable.idm.engine.IdmEngineConfiguration;
+import org.flowable.idm.engine.impl.UserQueryImpl;
+import org.flowable.idm.engine.impl.persistence.entity.UserEntity;
+import org.flowable.idm.engine.impl.persistence.entity.UserEntityImpl;
+import org.flowable.idm.engine.impl.persistence.entity.data.AbstractIdmDataManager;
+import org.flowable.idm.engine.impl.persistence.entity.data.UserDataManager;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+
+/**
+ * @Author: 土豆仙
+ * @Date: 2021/11/12 10:07
+ * @Description: 覆写用户信息查询
+ */
+@Slf4j
+@Component
+public class CustomUserDataManager extends AbstractIdmDataManager implements UserDataManager {
+ public CustomUserDataManager(IdmEngineConfiguration idmEngineConfiguration) {
+ super(idmEngineConfiguration);
+ }
+
+ @Autowired
+ @Lazy
+ private ManagementService managementService;
+
+ @Override
+ public Class extends UserEntity> getManagedEntityClass() {
+ return UserEntityImpl.class;
+ }
+
+ @Override
+ public UserEntity create() {
+ return new UserEntityImpl();
+ }
+
+ /**
+ *
+ * @param query 流程引擎查询参数
+ * @return 流程引擎展示视图
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public List findUserByQueryCriteria(UserQueryImpl query) {
+ if (log.isDebugEnabled()) {
+ log.debug("已重写自定义组查询:findUserByQueryCriteria");
+ }
+ UserQueryBo userQueryBo = transformQueryImplToUserQueryBo(query);
+
+ List users = managementService.executeCustomSql(new AbstractCustomSqlExecution>(CustomMybatisMapper.class) {
+ @Override
+ public List execute(CustomMybatisMapper customMybatisMapper) {
+ return customMybatisMapper.selectUserList(userQueryBo);
+ }
+ });
+
+ return users;
+ }
+
+ private UserQueryBo transformQueryImplToUserQueryBo(UserQueryImpl query) {
+ UserQueryBo userQueryBo = new UserQueryBo();
+
+ //设置userName
+ if (StringUtils.isNotBlank(query.getId())) {
+ userQueryBo.setUserName(query.getId());
+ } else {
+ userQueryBo.setUserName(query.getIdIgnoreCase());
+ }
+
+ userQueryBo.setUserNames(query.getIds());
+
+ //设置nickName
+ if (StringUtils.isNotBlank(query.getFirstName()) || StringUtils.isNotBlank(query.getLastName())) {
+ String nickName = StringUtils.join(query.getFirstName(), query.getLastName());
+ userQueryBo.setNickName(nickName);
+ } else {
+ userQueryBo.setNickName(query.getDisplayName());
+ }
+
+ //设置email
+ userQueryBo.setEmail(query.getEmail());
+ userQueryBo.setEmailLike(query.getEmailLike());
+
+
+ //处理组映射
+ List groupBoList = new ArrayList<>();
+ if (StringUtils.isNotEmpty(query.getGroupId())) {
+ groupBoList.add(new GroupCodeBo(query.getGroupId()));
+ }
+ if (!CollectionUtils.isEmpty(query.getGroupIds())) {
+
+ List collect = query.getGroupIds().stream()
+ .map(GroupCodeBo::new)
+ .collect(Collectors.toList());
+
+ groupBoList.addAll(collect);
+ }
+ userQueryBo.setGroupBoList(groupBoList);
+ return userQueryBo;
+ }
+
+ @Override
+ public long findUserCountByQueryCriteria(UserQueryImpl query) {
+ if (log.isDebugEnabled()) {
+ log.debug("已重写自定义组查询:findUserCountByQueryCriteria");
+ }
+ // return (Long) getDbSqlSession().selectOne("selectUserCountByQueryCriteria", query);
+ return findUserByQueryCriteria(query).size();
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public List findUsersByPrivilegeId(String privilegeId) {
+ if (log.isDebugEnabled()) {
+ log.debug("未重写自定义组查询:findUsersByPrivilegeId");
+ }
+ return getDbSqlSession().selectList("selectUsersWithPrivilegeId", privilegeId);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public List findUsersByNativeQuery(Map parameterMap) {
+ if (log.isDebugEnabled()) {
+ log.debug("未重写自定义组查询:findUsersByNativeQuery");
+ }
+ return getDbSqlSession().selectListWithRawParameter("selectUserByNativeQuery", parameterMap);
+ }
+
+ @Override
+ public long findUserCountByNativeQuery(Map parameterMap) {
+ if (log.isDebugEnabled()) {
+ log.debug("未重写自定义组查询:findUserCountByNativeQuery");
+ }
+ return (Long) getDbSqlSession().selectOne("selectUserCountByNativeQuery", parameterMap);
+ }
+}
diff --git a/ruoyi-extend/ruoyi-flow-ui/src/main/java/com/dromara/flow/ui/domain/bo/GroupCodeBo.java b/ruoyi-extend/ruoyi-flow-ui/src/main/java/com/dromara/flow/ui/domain/bo/GroupCodeBo.java
new file mode 100644
index 000000000..96fbaa3ca
--- /dev/null
+++ b/ruoyi-extend/ruoyi-flow-ui/src/main/java/com/dromara/flow/ui/domain/bo/GroupCodeBo.java
@@ -0,0 +1,120 @@
+package com.dromara.flow.ui.domain.bo;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.StrUtil;
+import liquibase.repackaged.org.apache.commons.text.StringSubstitutor;
+import lombok.NoArgsConstructor;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 业务组与流程组转换
+ * Author: 土豆仙
+ */
+@NoArgsConstructor
+public class GroupCodeBo {
+
+ /**
+ * 默认占位符号 代表所有
+ */
+ private static final String STAR = "*";
+
+ /**
+ * 分割符号
+ */
+ private static final String DOT = ".";
+
+ /**
+ * 占位字符串定义 - 后期放入配置中,用于扩展
+ */
+ private static final String PLACEHOLDER_STRING = "${deptCode}.${roleCode}";
+
+ /**
+ * 取 定义中 ${}内的内容
+ */
+ private static final String pattern = "\\$\\{(.*?)}";
+
+ /**
+ * deptCode:* 、roleCode:* ...
+ */
+ private Map codeMap = new HashMap<>();
+
+ /**
+ * deptCode:* 、roleCode:* ...
+ */
+ private static final Map codeMapInit = new HashMap<>();
+
+ /**
+ * deptCode、roleCode ...
+ */
+ private static final List codeList = new ArrayList<>();
+
+ //初始化
+ static {
+ Pattern p = Pattern.compile(pattern);
+ Matcher m = p.matcher(PLACEHOLDER_STRING);
+ while (m.find()) {
+ // ${}和 里面的内容
+ String code = m.group(1);
+ codeList.add(code);
+ codeMapInit.put(code, STAR);
+ }
+ }
+
+
+ public GroupCodeBo(String gourpCode) {
+ transferToBusiness(gourpCode);
+ }
+
+
+ /**
+ * @param gourpCode 流程引擎编码转换(约定)
+ */
+ public void transferToBusiness(String gourpCode) {
+
+ List split = StrUtil.split(gourpCode, DOT);
+ if (CollectionUtil.isNotEmpty(split) && split.size() == codeList.size()) {
+
+ //遍历
+ for (int i = 0; i < codeList.size(); i++) {
+ codeMap.put(codeList.get(i), split.get(i));
+ }
+ }
+ }
+
+
+ /**
+ * @return 组编码
+ */
+ public String getGourpCode() {
+
+ if (MapUtil.isEmpty(codeMap)) {
+ codeMap.putAll(codeMapInit);
+ }
+ StringSubstitutor strSubstitutor = new StringSubstitutor(codeMap);
+
+
+ return strSubstitutor.replace(PLACEHOLDER_STRING);
+ }
+
+
+ /**
+ * @return 编码-值 键值对
+ */
+ public Map getCodeMap() {
+
+ if (MapUtil.isEmpty(codeMap)) {
+ codeMap.putAll(codeMapInit);
+ }
+
+ return codeMap;
+
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-flow-ui/src/main/java/com/dromara/flow/ui/domain/bo/GroupNameBo.java b/ruoyi-extend/ruoyi-flow-ui/src/main/java/com/dromara/flow/ui/domain/bo/GroupNameBo.java
new file mode 100644
index 000000000..42b6c6bf0
--- /dev/null
+++ b/ruoyi-extend/ruoyi-flow-ui/src/main/java/com/dromara/flow/ui/domain/bo/GroupNameBo.java
@@ -0,0 +1,121 @@
+package com.dromara.flow.ui.domain.bo;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.StrUtil;
+import liquibase.repackaged.org.apache.commons.text.StringSubstitutor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 业务组名与流程组转换
+ * Author: 土豆仙
+ */
+@Data
+@NoArgsConstructor
+public class GroupNameBo {
+
+ /**
+ * 默认占位符号 代表所有
+ */
+ private static final String STAR = "*";
+
+ /**
+ * 分割符号
+ */
+ private static final String DOT = ".";
+
+ /**
+ * 占位字符串定义 - 后期放入配置中,用于扩展
+ */
+ private static final String PLACEHOLDER_STRING = "${deptName}.${roleName}";
+
+ /**
+ * 取 定义中 ${}内的内容
+ */
+ private static final String pattern = "\\$\\{(.*?)}";
+
+ /**
+ * deptName:* 、roleName:* ...
+ */
+ private static final Map nameMapInit = new HashMap<>();
+
+ /**
+ * deptName:* 、roleName:* ...
+ */
+ private Map nameMap = new HashMap<>();
+
+ /**
+ * deptName、roleName ...
+ */
+ private static final List nameList = new ArrayList<>();
+
+ //初始化
+ static {
+ Pattern p = Pattern.compile(pattern);
+ Matcher m = p.matcher(PLACEHOLDER_STRING);
+ while (m.find()) {
+ // ${}和 里面的内容
+ String Name = m.group(1);
+ nameList.add(Name);
+ nameMapInit.put(Name, STAR);
+ }
+ }
+
+
+ public GroupNameBo(String gourpName) {
+ transferToBusiness(gourpName);
+ }
+
+
+ /**
+ * @param gourpName 流程引擎编码转换(约定)
+ */
+ public void transferToBusiness(String gourpName) {
+
+ List split = StrUtil.split(gourpName, DOT);
+ if (CollectionUtil.isNotEmpty(split) && split.size() <= nameList.size()) {
+
+ //遍历
+ for (int i = 0; i < split.size(); i++) {
+ nameMap.put(nameList.get(i), split.get(i));
+ }
+ }
+ }
+
+ /**
+ * @return 组名
+ */
+ public String getGourpname() {
+
+ if (MapUtil.isEmpty(nameMap)) {
+ nameMap.putAll(nameMapInit);
+ }
+ StringSubstitutor strSubstitutor = new StringSubstitutor(nameMap);
+
+
+ return strSubstitutor.replace(PLACEHOLDER_STRING);
+ }
+
+
+ /**
+ * @return 名称编码-值 键值对
+ */
+ public Map getnameMap() {
+
+ if (MapUtil.isEmpty(nameMap)) {
+ nameMap.putAll(nameMapInit);
+ }
+
+ return nameMap;
+
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-flow-ui/src/main/java/com/dromara/flow/ui/domain/bo/GroupQueryBo.java b/ruoyi-extend/ruoyi-flow-ui/src/main/java/com/dromara/flow/ui/domain/bo/GroupQueryBo.java
new file mode 100644
index 000000000..fb4d0ded0
--- /dev/null
+++ b/ruoyi-extend/ruoyi-flow-ui/src/main/java/com/dromara/flow/ui/domain/bo/GroupQueryBo.java
@@ -0,0 +1,38 @@
+package com.dromara.flow.ui.domain.bo;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 自定义group查询条件
+ * Author: 土豆仙
+ */
+@Data
+public class GroupQueryBo {
+
+
+ //约定 解析为 区域code/部门code/角色code
+ /* protected String id;
+ protected List ids;*/
+
+ private boolean isReturnList = true;
+
+ // private DdrCodeDTO ddrCodeDTO;
+
+ private List groupCodeBos;
+
+ //约定 解析为 区域name/部门name/角色name
+ /* protected String name;
+ protected String nameLike;
+ protected String nameLikeIgnoreCase;*/
+
+ private GroupNameBo groupNameBo;
+
+ /*
+ protected String type;
+ protected String userId;
+ protected List userIds;*/
+
+ protected List userNames;
+}
diff --git a/ruoyi-extend/ruoyi-flow-ui/src/main/java/com/dromara/flow/ui/domain/bo/UserQueryBo.java b/ruoyi-extend/ruoyi-flow-ui/src/main/java/com/dromara/flow/ui/domain/bo/UserQueryBo.java
new file mode 100644
index 000000000..946263b83
--- /dev/null
+++ b/ruoyi-extend/ruoyi-flow-ui/src/main/java/com/dromara/flow/ui/domain/bo/UserQueryBo.java
@@ -0,0 +1,55 @@
+package com.dromara.flow.ui.domain.bo;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 自定义user查询条件
+ * Author: 土豆仙
+ */
+@Data
+public class UserQueryBo {
+
+ //用户ID -对应账号
+ /* protected String id;
+ protected List ids;
+ protected String idIgnoreCase;*/
+
+ private String userName;
+
+ private List userNames;
+
+ //用户名称
+ /*protected String firstName;
+ protected String firstNameLike;
+ protected String firstNameLikeIgnoreCase;
+ protected String lastName;
+ protected String lastNameLike;
+ protected String lastNameLikeIgnoreCase;
+ protected String fullNameLike;
+ protected String fullNameLikeIgnoreCase;
+ protected String displayName;
+ protected String displayNameLike;
+ protected String displayNameLikeIgnoreCase;*/
+
+ private String nickName;
+
+ //邮箱
+ /*protected String email;
+ protected String emailLike;*/
+
+ private String email;
+
+ private String emailLike;
+
+ //用户组
+ /*protected String groupId;
+ protected List groupIds;*/
+
+ //约定:用户组转换成 区化、部门、角色 最后使用稳定的code值
+ private List groupBoList;
+
+ //租户
+ protected String tenantId;
+}
diff --git a/ruoyi-extend/ruoyi-flow-ui/src/main/java/com/dromara/flow/ui/mapper/CustomMybatisMapper.java b/ruoyi-extend/ruoyi-flow-ui/src/main/java/com/dromara/flow/ui/mapper/CustomMybatisMapper.java
new file mode 100644
index 000000000..ea98b67e9
--- /dev/null
+++ b/ruoyi-extend/ruoyi-flow-ui/src/main/java/com/dromara/flow/ui/mapper/CustomMybatisMapper.java
@@ -0,0 +1,36 @@
+/* Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dromara.flow.ui.mapper;
+
+import com.dromara.flow.ui.domain.bo.GroupQueryBo;
+import com.dromara.flow.ui.domain.bo.UserQueryBo;
+import org.flowable.idm.api.Group;
+import org.flowable.idm.api.User;
+
+import java.util.List;
+
+/**
+ * 自定义mapperSQl
+ * Author: 土豆仙
+ */
+public interface CustomMybatisMapper {
+
+
+ List selectUserList(UserQueryBo userQueryBo);
+
+ /**
+ * @param groupQueryBo
+ * @return (id name)
+ */
+ List findGroupList(GroupQueryBo groupQueryBo);
+}
diff --git a/ruoyi-extend/ruoyi-flow-ui/src/main/resources/application-dev.yml b/ruoyi-extend/ruoyi-flow-ui/src/main/resources/application-dev.yml
new file mode 100644
index 000000000..431e8a8cc
--- /dev/null
+++ b/ruoyi-extend/ruoyi-flow-ui/src/main/resources/application-dev.yml
@@ -0,0 +1,38 @@
+--- # 监控配置
+spring.boot.admin.client:
+ # 增加客户端开关
+ enabled: true
+ # 设置 Spring Boot Admin Server 地址
+ url: http://localhost:9090/admin
+ instance:
+ service-host-type: IP
+ username: ruoyi
+ password: 123456
+# Spring配置
+spring:
+ application:
+ name: flow-ui
+ main:
+ allow-bean-definition-overriding: true
+ liquibase:
+ enabled: false
+# jackson:
+# date-format: yyyy-MM-dd HH:mm:ss
+ time-zone: GMT+8
+ # 资源信息
+ messages:
+ # 国际化资源文件路径
+ basename: i18n/messages
+ datasource:
+ url: jdbc:mysql://localhost:3306/ry-vue?zeroDateTimeBehavior=convertToNull&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false&nullCatalogMeansCurrent=true
+ username: root
+ password: 123456
+flowable:
+ databaseSchemaUpdate: true
+# databaseSchema:
+
+# 日志配置
+logging:
+ level:
+ org.flowable.engine.impl.persistence.entity.*: DEBUG
+ org.flowable.task.service.impl.persistence.entity.*: DEBUG # 日志配置
diff --git a/ruoyi-extend/ruoyi-flow-ui/src/main/resources/application-prod.yml b/ruoyi-extend/ruoyi-flow-ui/src/main/resources/application-prod.yml
new file mode 100644
index 000000000..431e8a8cc
--- /dev/null
+++ b/ruoyi-extend/ruoyi-flow-ui/src/main/resources/application-prod.yml
@@ -0,0 +1,38 @@
+--- # 监控配置
+spring.boot.admin.client:
+ # 增加客户端开关
+ enabled: true
+ # 设置 Spring Boot Admin Server 地址
+ url: http://localhost:9090/admin
+ instance:
+ service-host-type: IP
+ username: ruoyi
+ password: 123456
+# Spring配置
+spring:
+ application:
+ name: flow-ui
+ main:
+ allow-bean-definition-overriding: true
+ liquibase:
+ enabled: false
+# jackson:
+# date-format: yyyy-MM-dd HH:mm:ss
+ time-zone: GMT+8
+ # 资源信息
+ messages:
+ # 国际化资源文件路径
+ basename: i18n/messages
+ datasource:
+ url: jdbc:mysql://localhost:3306/ry-vue?zeroDateTimeBehavior=convertToNull&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false&nullCatalogMeansCurrent=true
+ username: root
+ password: 123456
+flowable:
+ databaseSchemaUpdate: true
+# databaseSchema:
+
+# 日志配置
+logging:
+ level:
+ org.flowable.engine.impl.persistence.entity.*: DEBUG
+ org.flowable.task.service.impl.persistence.entity.*: DEBUG # 日志配置
diff --git a/ruoyi-extend/ruoyi-flow-ui/src/main/resources/application.yml b/ruoyi-extend/ruoyi-flow-ui/src/main/resources/application.yml
new file mode 100644
index 000000000..f86deaa7f
--- /dev/null
+++ b/ruoyi-extend/ruoyi-flow-ui/src/main/resources/application.yml
@@ -0,0 +1,38 @@
+# 开发环境配置
+server:
+ # 服务器的HTTP端口,默认为8080
+ port: 9205
+ servlet:
+ # 应用的访问路径
+ context-path: /flowable-ui
+ tomcat:
+ # tomcat的URI编码
+ uri-encoding: UTF-8
+ # tomcat最大线程数,默认为200
+ #max-threads: 800
+ # Tomcat启动初始化的线程数,默认值25
+ #min-spare-threads: 30
+flowable:
+ customMybatisXMLMappers:
+ - mappers/CustomMybatisXmlMapper.xml
+ customMybatisMappers:
+ - com.dromara.flow.ui.mapper.CustomMybatisMapper
+--- # Actuator 监控端点的配置项
+management:
+ health:
+ ldap:
+ enabled: false
+ mail:
+ enabled: false
+ endpoints:
+ web:
+ exposure:
+ include: '*'
+ endpoint:
+ health:
+ show-details: ALWAYS
+ logfile:
+ external-file: ./logs/ruoyi-flow-ui.log
+spring:
+ profiles:
+ active: @profiles.active@
diff --git a/ruoyi-extend/ruoyi-flow-ui/src/main/resources/logback-plus.xml b/ruoyi-extend/ruoyi-flow-ui/src/main/resources/logback-plus.xml
new file mode 100644
index 000000000..589626fd1
--- /dev/null
+++ b/ruoyi-extend/ruoyi-flow-ui/src/main/resources/logback-plus.xml
@@ -0,0 +1,34 @@
+
+
+
+ logback
+
+
+
+
+
+
+ ${console.log.pattern}
+ utf-8
+
+
+
+
+ ${log.path}.log
+
+ ${log.path}.%d{yyyy-MM-dd}.log
+
+ 60
+
+
+ ${log.pattern}
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-extend/ruoyi-flow-ui/src/main/resources/mappers/CustomMybatisXmlMapper.xml b/ruoyi-extend/ruoyi-flow-ui/src/main/resources/mappers/CustomMybatisXmlMapper.xml
new file mode 100644
index 000000000..088545413
--- /dev/null
+++ b/ruoyi-extend/ruoyi-flow-ui/src/main/resources/mappers/CustomMybatisXmlMapper.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-extend/ruoyi-flow-ui/src/test/java/org/dromara/flow/ui/RuoyiFlowUiApplicationTests.java b/ruoyi-extend/ruoyi-flow-ui/src/test/java/org/dromara/flow/ui/RuoyiFlowUiApplicationTests.java
new file mode 100644
index 000000000..cd4c0bcb7
--- /dev/null
+++ b/ruoyi-extend/ruoyi-flow-ui/src/test/java/org/dromara/flow/ui/RuoyiFlowUiApplicationTests.java
@@ -0,0 +1,13 @@
+package org.dromara.flow.ui;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class RuoyiFlowUiApplicationTests {
+
+ @Test
+ void contextLoads() {
+ }
+
+}