فهرست منبع

Merge remote-tracking branch 'origin/dev' into dev

大数据与最优化研究所 1 سال پیش
والد
کامیت
151ebb93a1

+ 13 - 0
src/main/java/com/xjrsoft/common/mybatis/FeatureCondition.java

@@ -0,0 +1,13 @@
+package com.xjrsoft.common.mybatis;
+
+import java.io.Serializable;
+
+//条件实体
+public class FeatureCondition implements Serializable {
+    //列名
+    public String filedName;
+    //条件
+    public String fieldCondition;
+    //列值
+    public String value;
+}

+ 508 - 0
src/main/java/com/xjrsoft/common/mybatis/SqlRunnerAdapter.java

@@ -0,0 +1,508 @@
+package com.xjrsoft.common.mybatis;
+
+import cn.hutool.db.DbRuntimeException;
+import cn.hutool.db.Entity;
+import cn.hutool.db.meta.Column;
+import cn.hutool.db.meta.Table;
+import cn.hutool.db.meta.TableType;
+import com.baomidou.mybatisplus.core.assist.ISqlRunner;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.ibatis.jdbc.SQL;
+import org.apache.ibatis.logging.Log;
+import org.apache.ibatis.logging.LogFactory;
+import org.apache.ibatis.session.SqlSession;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.mybatis.spring.SqlSessionUtils;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.io.Closeable;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+public class SqlRunnerAdapter implements ISqlRunner, Closeable {
+
+    private final Log log = LogFactory.getLog(SqlRunnerAdapter.class);
+
+    public static final SqlRunnerAdapter DEFAULT = new SqlRunnerAdapter();
+    // 默认FACTORY
+    private SqlSessionFactory sqlSessionFactory;
+
+    private Class<?> clazz;
+
+    public SqlRunnerAdapter() {
+        this.sqlSessionFactory = SqlHelper.FACTORY;
+    }
+
+    public SqlRunnerAdapter(Class<?> clazz) {
+        this.clazz = clazz;
+    }
+
+    /**
+     * 获取默认的SqlQuery(适用于单库)
+     *
+     * @return ignore
+     */
+    public static SqlRunnerAdapter db() {
+        // 初始化的静态变量 还是有前后加载的问题 该判断只会执行一次
+        if (DEFAULT.sqlSessionFactory == null) {
+            DEFAULT.sqlSessionFactory = SqlHelper.FACTORY;
+        }
+        return DEFAULT;
+    }
+
+    /**
+     * 根据当前class对象获取SqlQuery(适用于多库)
+     *
+     * @param clazz ignore
+     * @return ignore
+     */
+    public static SqlRunnerAdapter db(Class<?> clazz) {
+        return new SqlRunnerAdapter(clazz);
+    }
+
+    @Transactional
+    @Override
+    public boolean insert(String sql, Object... args) {
+        SqlSession sqlSession = sqlSession();
+        try {
+            return SqlHelper.retBool(sqlSession.insert(INSERT, sqlMap(sql, args)));
+        } finally {
+            closeSqlSession(sqlSession);
+        }
+    }
+
+    @Transactional
+    @Override
+    public boolean delete(String sql, Object... args) {
+        SqlSession sqlSession = sqlSession();
+        try {
+            return SqlHelper.retBool(sqlSession.delete(DELETE, sqlMap(sql, args)));
+        } finally {
+            closeSqlSession(sqlSession);
+        }
+    }
+
+    /**
+     * 获取sqlMap参数
+     *
+     * @param sql  指定参数的格式: {0}, {1}
+     * @param args 仅支持String
+     * @return ignore
+     */
+    private Map<String, String> sqlMap(String sql, Object... args) {
+        Map<String, String> sqlMap = CollectionUtils.newHashMapWithExpectedSize(1);
+        sqlMap.put(SQL, StringUtils.sqlArgsFill(sql, args));
+        return sqlMap;
+    }
+
+    /**
+     * 获取sqlMap参数
+     *
+     * @param sql  指定参数的格式: {0}, {1}
+     * @param page 分页模型
+     * @param args 仅支持String
+     * @return ignore
+     */
+    private Map<String, Object> sqlMap(String sql, IPage<?> page, Object... args) {
+        Map<String, Object> sqlMap = CollectionUtils.newHashMapWithExpectedSize(2);
+        sqlMap.put(PAGE, page);
+        sqlMap.put(SQL, StringUtils.sqlArgsFill(sql, args));
+        return sqlMap;
+    }
+
+    @Transactional
+    @Override
+    public boolean update(String sql, Object... args) {
+        SqlSession sqlSession = sqlSession();
+        try {
+            return SqlHelper.retBool(sqlSession.update(UPDATE, sqlMap(sql, args)));
+        } finally {
+            closeSqlSession(sqlSession);
+        }
+    }
+
+    /**
+     * 根据sql查询Map结果集
+     * <p>SqlRunner.db().selectList("select * from tbl_user where name={0}", "Caratacus")</p>
+     *
+     * @param sql  sql语句,可添加参数,格式:{0},{1}
+     * @param args 只接受String格式
+     * @return ignore
+     */
+    @Override
+    public List<Map<String, Object>> selectList(String sql, Object... args) {
+        SqlSession sqlSession = sqlSession();
+        try {
+            return sqlSession.selectList(SELECT_LIST, sqlMap(sql, args));
+        } finally {
+            closeSqlSession(sqlSession);
+        }
+    }
+
+    /**
+     * 根据sql查询一个字段值的结果集
+     * <p>注意:该方法只会返回一个字段的值, 如果需要多字段,请参考{@code selectList()}</p>
+     *
+     * @param sql  sql语句,可添加参数,格式:{0},{1}
+     * @param args 只接受String格式
+     * @return ignore
+     */
+    @Override
+    public List<Object> selectObjs(String sql, Object... args) {
+        SqlSession sqlSession = sqlSession();
+        try {
+            return sqlSession.selectList(SELECT_OBJS, sqlMap(sql, args));
+        } finally {
+            closeSqlSession(sqlSession);
+        }
+    }
+
+    /**
+     * 根据sql查询一个字段值的一条结果
+     * <p>注意:该方法只会返回一个字段的值, 如果需要多字段,请参考{@code selectOne()}</p>
+     *
+     * @param sql  sql语句,可添加参数,格式:{0},{1}
+     * @param args 只接受String格式
+     * @return ignore
+     */
+    @Override
+    public Object selectObj(String sql, Object... args) {
+        return SqlHelper.getObject(log, selectObjs(sql, args));
+    }
+
+    @Override
+    public long selectCount(String sql, Object... args) {
+        SqlSession sqlSession = sqlSession();
+        try {
+            return SqlHelper.retCount(sqlSession.<Long>selectOne(COUNT, sqlMap(sql, args)));
+        } finally {
+            closeSqlSession(sqlSession);
+        }
+    }
+
+    @Override
+    public Map<String, Object> selectOne(String sql, Object... args) {
+        return SqlHelper.getObject(log, selectList(sql, args));
+    }
+
+    @Override
+    public <E extends IPage<Map<String, Object>>> E selectPage(E page, String sql, Object... args) {
+        if (null == page) {
+            return null;
+        }
+        SqlSession sqlSession = sqlSession();
+        try {
+            page.setRecords(sqlSession.selectList(SELECT_LIST, sqlMap(sql, page, args)));
+        } finally {
+            closeSqlSession(sqlSession);
+        }
+        return page;
+    }
+
+    /**
+     * 获取Session 默认自动提交
+     */
+    private SqlSession sqlSession() {
+        return SqlSessionUtils.getSqlSession(getSqlSessionFactory());
+    }
+
+    /**
+     * 释放sqlSession
+     *
+     * @param sqlSession session
+     */
+    private void closeSqlSession(SqlSession sqlSession) {
+        SqlSessionUtils.closeSqlSession(sqlSession, getSqlSessionFactory());
+    }
+
+    /**
+     * 获取SqlSessionFactory
+     */
+    private SqlSessionFactory getSqlSessionFactory() {
+        return Optional.ofNullable(clazz).map(GlobalConfigUtils::currentSessionFactory).orElse(sqlSessionFactory);
+    }
+
+    @Override
+    public void close() {
+        DEFAULT.sqlSessionFactory = null;
+    }
+
+    @Transactional
+    public Boolean dynamicInsert(String tableName, Entity params) {
+        ImmutablePair<String, List<String>> sql = dynamicInsertBuild(tableName, params);
+        //执行sql
+//        long keyValue = IdUtil.getSnowflakeNextId();
+//        String sql = "insert into official_document_received(communication_number,emergency_level,document_level,communication_org,received_date,checkout_time,file_id,received_title,received_type,received_number,id,create_user_id,create_date,delete_mark,enabled_mark) VALUES ('12312','emergency_level2','document_level1','asdfasd','2024-02-26','2024-02-26 00:06:00','1761947003676405762','发生的发生的newnewnewnnewnewnewewewewe','rt_administrative','123123','" + keyValue + "','1000000000000000000','2024-02-27 17:43:59.140274','0','1')";
+        return this.insert(sql.left, sql.right.toArray());
+    }
+
+    @Transactional
+    public Boolean dynamicInsertBatch(String tableName, List<Entity> params) {
+        SqlSession sqlSession = sqlSession();
+        try {
+            for (Entity param : params) {
+                ImmutablePair<String, List<String>> sql = dynamicInsertBuild(tableName, param);
+                boolean result = SqlHelper.retBool(sqlSession.insert(INSERT, sqlMap(sql.left, sql.right.toArray())));
+                if (!result) return false;
+            }
+            return true;
+        } finally {
+            closeSqlSession(sqlSession);
+        }
+    }
+
+    private ImmutablePair<String, List<String>> dynamicInsertBuild(String tableName, Entity params) {
+        SQL sql = new SQL().INSERT_INTO(tableName);
+        List<String> args = new ArrayList<>();
+        int i = 0;
+
+        // 循环字段列表并赋值
+        for (String key : params.keySet()) {
+            Object value = params.get(key);
+            if (value == null) {
+                continue;
+            }
+            String strValue = value.toString();
+            sql.INTO_COLUMNS(key);
+            sql.INTO_VALUES(String.format("{%d}", i));
+            args.add(strValue);
+            i++;
+        }
+
+        return new ImmutablePair<>(sql.toString(), args);
+    }
+
+    @Transactional
+    public Boolean dynamicUpdate(String tableName, Entity params, Entity where) {
+        SQL sql = new SQL().UPDATE(tableName);
+        List<String> args = new ArrayList<>();
+        int i = 0;
+        // 循环字段列表并赋值
+        for (String key : params.keySet()) {
+            Object value = params.get(key);
+            if (value == null) {
+                continue;
+            }
+            String strValue = value.toString();
+            sql.SET(String.format("%s={%d}", key, i));
+            args.add(strValue);
+            i++;
+        }
+
+        // 循环where条件
+        for (String key : where.keySet()) {
+            Object value = where.get(key);
+            if (value == null) {
+                continue;
+            }
+            // 判断参数是否是数组
+            if (value instanceof ArrayList) {
+                List<String> vp = new ArrayList<>();
+                for (Object v : ((ArrayList<?>) value)) {
+                    vp.add(String.format("{%d}",i));
+                    args.add(v.toString());
+                    i++;
+                }
+                sql.WHERE(String.format("%s in (%s)", key, String.join(",",vp)));
+            } else {
+                String strValue = value.toString();
+                sql.WHERE(String.format("%s={%d}", key, i));
+                args.add(strValue);
+                i++;
+            }
+
+        }
+
+        //执行sql
+        return this.update(sql.toString(), args.toArray());
+    }
+
+    @Transactional
+    public Boolean dynamicDelete(String tableName, Entity where) {
+        SQL sql = new SQL().DELETE_FROM(tableName);
+        List<String> args = new ArrayList<>();
+        int i = 0;
+
+        // 循环where条件
+        for (String key : where.keySet()) {
+            Object value = where.get(key);
+            if (value == null) {
+                continue;
+            }
+            // 判断参数是否是数组
+            if (value instanceof ArrayList) {
+                List<String> vp = new ArrayList<>();
+                for (Object v : ((ArrayList<?>) value)) {
+                    vp.add(String.format("{%d}",i));
+                    args.add(v.toString());
+                    i++;
+                }
+                sql.WHERE(String.format("%s in (%s)", key, String.join(",",vp)));
+            } else {
+                String strValue = value.toString();
+                sql.WHERE(String.format("%s={%d}", key, i));
+                args.add(strValue);
+                i++;
+            }
+        }
+
+        //执行sql
+        return this.delete(sql.toString(), args.toArray());
+    }
+
+    /**
+     * 查询单条数据
+     *
+     * @param tableName
+     * @param where
+     * @return
+     */
+    public Map<String, Object> dynamicSelectOne(String tableName, Entity where) {
+        SQL sql = new SQL().FROM(tableName);
+        List<String> args = new ArrayList<>();
+        int i = 0;
+        // 查询列
+        for (String field : where.getFieldNames()) {
+            sql.SELECT(field);
+        }
+
+        // 循环where条件
+        for (String key : where.keySet()) {
+            Object value = where.get(key);
+            if (value == null) {
+                continue;
+            }
+            String strValue = value.toString();
+            sql.WHERE(String.format("%s={%d}", key, i));
+            args.add(strValue);
+            i++;
+        }
+        return this.selectOne(sql.toString(), args.toArray());
+    }
+
+    /**
+     * 按条件查询数据
+     *
+     * @param tableName
+     * @param where
+     * @return
+     */
+    public List<Map<String, Object>> dynamicSelect(String tableName, Entity where) {
+        SQL sql = new SQL().FROM(tableName);
+        List<String> args = new ArrayList<>();
+        int i = 0;
+        // 查询列
+        for (String field : where.getFieldNames()) {
+            sql.SELECT(field);
+        }
+
+        // 循环where条件
+        for (String key : where.keySet()) {
+            Object value = where.get(key);
+            if (value == null) {
+                continue;
+            }
+            String strValue = value.toString();
+            sql.WHERE(String.format("%s={%d}", key, i));
+            args.add(strValue);
+            i++;
+        }
+        return this.selectList(sql.toString(), args.toArray());
+    }
+
+    public <E extends IPage<Map<String, Object>>> E dynamicSelectPage(E page, String tableName, Entity where) {
+        SQL sql = new SQL().FROM(tableName);
+        List<String> args = new ArrayList<>();
+        int i = 0;
+        // 查询列
+        for (String field : where.getFieldNames()) {
+            sql.SELECT(field);
+        }
+
+        // 循环where条件
+        for (String key : where.keySet()) {
+            Object value = where.get(key);
+            if (value == null) {
+                continue;
+            }
+            String strValue = value.toString();
+            sql.WHERE(String.format("%s={%d}", key, i));
+            args.add(strValue);
+            i++;
+        }
+        return this.selectPage(page, sql.toString(), args.toArray());
+    }
+
+    /**
+     * 获得表的元信息<br>
+     * 注意如果需要获取注释,某些数据库如MySQL,需要在配置中添加:
+     * <pre>
+     *     remarks = true
+     *     useInformationSchema = true
+     * </pre>
+     *
+     * @param tableName 表名
+     * @return Table对象
+     */
+    public Table getTableMeta(String tableName) {
+        final Table table = Table.create(tableName);
+        // 获取 SqlSession 对象
+        SqlSession sqlSession = sqlSessionFactory.openSession();
+        Connection conn = null;
+        try {
+            conn = sqlSession.getConnection();
+
+            // catalog和schema获取失败默认使用null代替
+            final String catalog = conn.getCatalog();
+            table.setCatalog(catalog);
+            final String schema = conn.getSchema();
+            table.setSchema(schema);
+
+            final DatabaseMetaData metaData = conn.getMetaData();
+
+            // 获得表元数据(表注释)
+            try (ResultSet rs = metaData.getTables(catalog, schema, tableName, new String[]{TableType.TABLE.value()})) {
+                if (null != rs) {
+                    if (rs.next()) {
+                        table.setComment(rs.getString("REMARKS"));
+                    }
+                }
+            }
+
+            // 获得主键
+            try (ResultSet rs = metaData.getPrimaryKeys(catalog, schema, tableName)) {
+                if (null != rs) {
+                    while (rs.next()) {
+                        table.addPk(rs.getString("COLUMN_NAME"));
+                    }
+                }
+            }
+
+            // 获得列
+            try (ResultSet rs = metaData.getColumns(catalog, schema, tableName, null)) {
+                if (null != rs) {
+                    while (rs.next()) {
+                        table.setColumn(Column.create(table, rs));
+                    }
+                }
+            }
+
+        } catch (SQLException e) {
+            throw new DbRuntimeException("Get columns error!", e);
+        } finally {
+            closeSqlSession(sqlSession);
+        }
+        return table;
+    }
+}

+ 209 - 0
src/main/java/com/xjrsoft/common/mybatis/Table.java

@@ -0,0 +1,209 @@
+package com.xjrsoft.common.mybatis;
+
+import cn.hutool.db.meta.Column;
+
+import java.io.Serializable;
+import java.util.*;
+
+/**
+ * 数据库表信息
+ *
+ * @author loolly
+ */
+public class Table implements Serializable, Cloneable {
+
+    /**
+     * table所在的schema
+     */
+    private String schema;
+    /**
+     * tables所在的catalog
+     */
+    private String catalog;
+    /**
+     * 表名
+     */
+    private String tableName;
+    /**
+     * 注释
+     */
+    private String comment;
+    /**
+     * 主键字段名列表
+     */
+    private Set<String> pkNames = new LinkedHashSet<>();
+    private final Map<String, Column> columns = new LinkedHashMap<>();
+
+    public static Table create(String tableName) {
+        return new Table(tableName);
+    }
+
+    // ----------------------------------------------------- Constructor start
+
+    /**
+     * 构造
+     *
+     * @param tableName 表名
+     */
+    public Table(String tableName) {
+        this.setTableName(tableName);
+    }
+    // ----------------------------------------------------- Constructor end
+
+    // ----------------------------------------------------- Getters and Setters start
+
+    /**
+     * 获取 schema
+     *
+     * @return schema
+     * @since 5.4.3
+     */
+    public String getSchema() {
+        return schema;
+    }
+
+    /**
+     * 设置schema
+     *
+     * @param schema schema
+     * @return this
+     * @since 5.4.3
+     */
+    public Table setSchema(String schema) {
+        this.schema = schema;
+        return this;
+    }
+
+    /**
+     * 获取catalog
+     *
+     * @return catalog
+     * @since 5.4.3
+     */
+    public String getCatalog() {
+        return catalog;
+    }
+
+    /**
+     * 设置catalog
+     *
+     * @param catalog catalog
+     * @return this
+     * @since 5.4.3
+     */
+    public Table setCatalog(String catalog) {
+        this.catalog = catalog;
+        return this;
+    }
+
+    /**
+     * 获取表名
+     *
+     * @return 表名
+     */
+    public String getTableName() {
+        return tableName;
+    }
+
+    /**
+     * 设置表名
+     *
+     * @param tableName 表名
+     */
+    public void setTableName(String tableName) {
+        this.tableName = tableName;
+    }
+
+    /**
+     * 获取注释
+     *
+     * @return 注释
+     */
+    public String getComment() {
+        return comment;
+    }
+
+    /**
+     * 设置注释
+     *
+     * @param comment 注释
+     * @return this
+     */
+    public Table setComment(String comment) {
+        this.comment = comment;
+        return this;
+    }
+
+    /**
+     * 获取主键列表
+     *
+     * @return 主键列表
+     */
+    public Set<String> getPkNames() {
+        return pkNames;
+    }
+
+    /**
+     * 给定列名是否为主键
+     *
+     * @param columnName 列名
+     * @return 是否为主键
+     * @since 5.4.3
+     */
+    public boolean isPk(String columnName) {
+        return getPkNames().contains(columnName);
+    }
+
+    /**
+     * 设置主键列表
+     *
+     * @param pkNames 主键列表
+     */
+    public void setPkNames(Set<String> pkNames) {
+        this.pkNames = pkNames;
+    }
+    // ----------------------------------------------------- Getters and Setters end
+
+    /**
+     * 设置列对象
+     *
+     * @param column 列对象
+     * @return 自己
+     */
+    public Table setColumn(Column column) {
+        this.columns.put(column.getName(), column);
+        return this;
+    }
+
+    /**
+     * 获取某列信息
+     *
+     * @param name 列名
+     * @return 列对象
+     * @since 4.2.2
+     */
+    public Column getColumn(String name) {
+        return this.columns.get(name);
+    }
+
+    /**
+     * 获取所有字段元信息
+     *
+     * @return 字段元信息集合
+     * @since 4.5.8
+     */
+    public Collection<Column> getColumns() {
+        return this.columns.values();
+    }
+
+    /**
+     * 添加主键
+     *
+     * @param pkColumnName 主键的列名
+     * @return 自己
+     */
+    public Table addPk(String pkColumnName) {
+        this.pkNames.add(pkColumnName);
+        return this;
+    }
+}

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 207 - 240
src/main/java/com/xjrsoft/module/form/service/impl/FormExecuteServiceImpl.java


+ 2389 - 0
src/main/java/com/xjrsoft/module/form/service/impl/FormExecuteServiceImpl.java.back

@@ -0,0 +1,2389 @@
+package com.xjrsoft.module.form.service.impl;
+
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.ClassUtil;
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.db.Db;
+import cn.hutool.db.DbUtil;
+import cn.hutool.db.Entity;
+import cn.hutool.db.GlobalDbConfig;
+import cn.hutool.db.Page;
+import cn.hutool.db.PageResult;
+import cn.hutool.db.Session;
+import cn.hutool.db.dialect.DialectFactory;
+import cn.hutool.db.meta.Column;
+import cn.hutool.db.meta.JdbcType;
+import cn.hutool.db.meta.MetaUtil;
+import cn.hutool.db.meta.Table;
+import cn.hutool.db.sql.Condition;
+import cn.hutool.db.sql.Direction;
+import cn.hutool.db.sql.Order;
+import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.annotation.DbType;
+import com.baomidou.mybatisplus.core.toolkit.StringPool;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.xjrsoft.common.constant.GlobalConstant;
+import com.xjrsoft.common.enums.DeleteMark;
+import com.xjrsoft.common.enums.EnabledMark;
+import com.xjrsoft.common.enums.OracleFieldsType;
+import com.xjrsoft.common.exception.MyException;
+import com.xjrsoft.common.handler.XjrEntityHandler;
+import com.xjrsoft.common.handler.XjrEntityListHandler;
+import com.xjrsoft.common.model.generator.ComponentConfig;
+import com.xjrsoft.common.page.PageOutput;
+import com.xjrsoft.common.runner.XjrSqlConnRunner;
+import com.xjrsoft.common.utils.DatasourceUtil;
+import com.xjrsoft.common.utils.JdbcToJavaUtil;
+import com.xjrsoft.common.utils.LocalDateTimeUtil;
+import com.xjrsoft.module.app.entity.AppFuncDesign;
+import com.xjrsoft.module.app.service.IAppFuncDesignService;
+import com.xjrsoft.module.authority.utils.AuthorityUtil;
+import com.xjrsoft.module.form.dto.AppFormExecuteAddOrUpdateDto;
+import com.xjrsoft.module.form.dto.AppFormExecuteDeleteDto;
+import com.xjrsoft.module.form.dto.AppFormExecuteInfoDto;
+import com.xjrsoft.module.form.dto.AppFormExecuteListDto;
+import com.xjrsoft.module.form.dto.AppFormExecutePageDto;
+import com.xjrsoft.module.form.dto.FormExecuteAddOrUpdateDto;
+import com.xjrsoft.module.form.dto.FormExecuteDeleteDto;
+import com.xjrsoft.module.form.dto.FormExecuteInfoDto;
+import com.xjrsoft.module.form.dto.FormExecuteListDto;
+import com.xjrsoft.module.form.dto.FormExecutePageDto;
+import com.xjrsoft.module.form.dto.FormExecuteWorkflowAddDto;
+import com.xjrsoft.module.form.dto.FormExecuteWorkflowInfoDto;
+import com.xjrsoft.module.form.dto.FormExecuteWorkflowUpdateDto;
+import com.xjrsoft.module.form.entity.FormDesignConfig;
+import com.xjrsoft.module.form.entity.FormRelease;
+import com.xjrsoft.module.form.entity.FormReleaseConfig;
+import com.xjrsoft.module.form.entity.FormTemplate;
+import com.xjrsoft.module.form.mapper.FormReleaseMapper;
+import com.xjrsoft.module.form.mapper.FormTemplateMapper;
+import com.xjrsoft.module.form.service.IFormExecuteService;
+import com.xjrsoft.module.form.utils.FormDataTransUtil;
+import com.xjrsoft.module.form.vo.DeskColumnsVo;
+import com.xjrsoft.module.form.vo.DeskTableInfoVo;
+import com.xjrsoft.module.generator.constant.ComponentTypeConstant;
+import com.xjrsoft.module.generator.entity.ColumnConfig;
+import com.xjrsoft.module.generator.entity.ListConfig;
+import com.xjrsoft.module.generator.entity.QueryConfig;
+import com.xjrsoft.module.generator.entity.TableConfig;
+import com.xjrsoft.module.generator.entity.TableFieldConfig;
+import com.xjrsoft.module.generator.entity.TableStructureConfig;
+import com.xjrsoft.module.generator.utils.GeneratorUtil;
+import com.xjrsoft.module.system.service.ICodeRuleService;
+import lombok.AllArgsConstructor;
+import lombok.SneakyThrows;
+import net.sf.jsqlparser.expression.Expression;
+import net.sf.jsqlparser.expression.LongValue;
+import net.sf.jsqlparser.expression.StringValue;
+import net.sf.jsqlparser.expression.TimestampValue;
+import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
+import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
+import net.sf.jsqlparser.expression.operators.relational.GreaterThanEquals;
+import net.sf.jsqlparser.expression.operators.relational.LikeExpression;
+import net.sf.jsqlparser.expression.operators.relational.MinorThanEquals;
+import net.sf.jsqlparser.statement.select.PlainSelect;
+import net.sf.jsqlparser.statement.select.Select;
+import net.sf.jsqlparser.util.SelectUtils;
+import org.apache.commons.collections.MapUtils;
+import org.apache.commons.lang3.BooleanUtils;
+import org.apache.commons.lang3.tuple.ImmutableTriple;
+import org.apache.commons.lang3.tuple.Triple;
+import org.camunda.bpm.engine.impl.calendar.DateTimeUtil;
+import org.springframework.stereotype.Service;
+
+import javax.sql.DataSource;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * @Author: tzx
+ * @Date: 2022/5/11 15:05
+ */
+@Service
+@AllArgsConstructor
+public class FormExecuteServiceImpl implements IFormExecuteService {
+
+    private final FormReleaseMapper formReleaseMapper;
+
+    private final FormTemplateMapper formTemplateMapper;
+
+    private final ICodeRuleService codeRuleService;
+
+    private final IAppFuncDesignService appFuncDesignService;
+
+    /**
+     * 需要模糊查询的
+     */
+    private final List<String> LIKE_CLASS_NAME = Collections.singletonList("String");
+
+    /**
+     * 需要完全对比判断
+     */
+    private final List<String> EQ_CLASS_NAME = Arrays.asList("Integer", "Long", "Double", "Float", "Boolean");
+
+    /**
+     * 时间类型
+     */
+    private final List<String> TIME_CLASS_NAME = Collections.singletonList("LocalDateTime");
+
+    @Override
+    @SneakyThrows
+    public List<Entity> list(FormExecuteListDto dto) {
+        FormRelease formRelease = formReleaseMapper.selectById(dto.getReleaseId());
+
+        String configJson = formRelease.getConfigJson();
+
+        //发布配置
+        FormReleaseConfig formReleaseConfig = JSONUtil.toBean(configJson, FormReleaseConfig.class);
+
+        //自定义表单数据
+        FormTemplate template = formTemplateMapper.selectById(formRelease.getFormId());
+
+        String formJson = template.getFormJson();
+        //自定义表单配置
+        FormDesignConfig formDesignConfig = JSONUtil.toBean(formJson, FormDesignConfig.class);
+
+        List<TableConfig> tableConfigs = formDesignConfig.getTableConfigs();
+        //主表
+        Optional<TableConfig> mainTable = tableConfigs.stream().filter(TableConfig::getIsMain).findFirst();
+
+        if (mainTable.isPresent()) {
+            TableConfig tableConfig = mainTable.get();
+            String tableName = tableConfig.getTableName();
+
+            List<ColumnConfig> columnConfigs = formReleaseConfig.getListConfig().getColumnConfigs();
+            List<String> fieldsList = columnConfigs.stream().map(ColumnConfig::getColumnName).collect(Collectors.toList());
+            // 添加权限所属人字段返回
+            if (BooleanUtils.isTrue(formDesignConfig.getIsDataAuth())) {
+                fieldsList.add(GlobalConstant.AUTH_USER_ID);
+            }
+
+            List<Entity> listData = getListDataByExpression(tableName, fieldsList, formDesignConfig, formReleaseConfig, dto.getParams());
+            if (dto.getIsTrans()) {
+                // 关联数据显示转换
+                FormDataTransUtil.transData(listData, formDesignConfig);
+            }
+            return listData;
+        } else {
+            throw new MyException("主表不存在");
+        }
+
+    }
+
+    @Override
+    public List<Entity> appList(AppFormExecuteListDto dto) {
+
+        AppFuncDesign funcDesign = appFuncDesignService.getById(dto.getFuncId());
+//        FormRelease formRelease = formReleaseMapper.selectById(dto.getReleaseId());
+
+        String configJson = funcDesign.getJsonContent();
+
+        //发布配置
+        FormReleaseConfig formReleaseConfig = JSONUtil.toBean(configJson, FormReleaseConfig.class);
+
+        //自定义表单配置
+        FormDesignConfig formDesignConfig = JSONUtil.toBean(configJson, FormDesignConfig.class);
+
+        List<TableConfig> tableConfigs = formDesignConfig.getTableConfigs();
+        //主表
+        Optional<TableConfig> mainTable = tableConfigs.stream().filter(TableConfig::getIsMain).findFirst();
+
+        if (mainTable.isPresent()) {
+            TableConfig tableConfig = mainTable.get();
+            String tableName = tableConfig.getTableName();
+
+            List<ColumnConfig> columnConfigs = formReleaseConfig.getListConfig().getColumnConfigs();
+            List<String> fieldsList = columnConfigs.stream().map(ColumnConfig::getColumnName).collect(Collectors.toList());
+            // 添加权限所属人字段返回
+            if (BooleanUtils.isTrue(formDesignConfig.getIsDataAuth())) {
+                fieldsList.add(GlobalConstant.AUTH_USER_ID);
+            }
+
+            List<Entity> listData = getListDataByExpression(tableName, fieldsList, formDesignConfig, formReleaseConfig, dto.getParams());
+            if (dto.getIsTrans()) {
+                // 关联数据显示转换
+                FormDataTransUtil.transData(listData, formDesignConfig);
+            }
+            return listData;
+        } else {
+            throw new MyException("主表不存在");
+        }
+    }
+
+    @Override
+    public PageOutput<Entity> page(FormExecutePageDto dto) {
+
+        FormRelease formRelease = formReleaseMapper.selectById(dto.getReleaseId());
+
+        String configJson = formRelease.getConfigJson();
+
+        //发布配置
+        FormReleaseConfig formReleaseConfig = JSONUtil.toBean(configJson, FormReleaseConfig.class);
+
+        //自定义表单数据
+        FormTemplate template = formTemplateMapper.selectById(formRelease.getFormId());
+
+        String formJson = template.getFormJson();
+        //自定义表单配置
+        FormDesignConfig formDesignConfig = JSONUtil.toBean(formJson, FormDesignConfig.class);
+
+        List<TableConfig> tableConfigs = formDesignConfig.getTableConfigs();
+        //主表
+        Optional<TableConfig> mainTable = tableConfigs.stream().filter(TableConfig::getIsMain).findFirst();
+
+        if (mainTable.isPresent()) {
+            TableConfig tableConfig = mainTable.get();
+            String tableName = tableConfig.getTableName();
+
+            //构建分页参数
+            Page page = new Page(dto.getLimit() - 1, dto.getSize());
+            String field = dto.getField();
+            String orderStr = dto.getOrder();
+            ListConfig listConfig = formReleaseConfig.getListConfig();
+            if (StrUtil.isBlank(field)) {
+                field = StrUtil.emptyToDefault(listConfig.getOrderBy(), tableConfig.getPkField());
+                orderStr = StrUtil.emptyToDefault(listConfig.getOrderType(), "desc");
+            }
+            if (StrUtil.isNotBlank(field)) {
+                Order order = new Order();
+                order.setDirection(Direction.ASC);
+                if (orderStr.equals("descend") || orderStr.equals("desc")) {
+                    order.setDirection(Direction.DESC);
+                }
+//                order.setDirection(StrUtil.equalsIgnoreCase(orderStr, "descend") ? Direction.DESC : Direction.ASC);
+                order.setField(field);
+                page.setOrder(order);
+            }
+
+            List<ColumnConfig> columnConfigs = listConfig.getColumnConfigs();
+            Set<String> fieldsList = columnConfigs.stream().map(ColumnConfig::getColumnName).collect(Collectors.toSet());
+            // 添加权限所属人字段返回
+            if (BooleanUtils.isTrue(formDesignConfig.getIsDataAuth())) {
+                fieldsList.add(GlobalConstant.AUTH_USER_ID);
+            }
+
+            PageOutput<Entity> pageData = getPageDataByExpression(tableName, fieldsList, formDesignConfig, formReleaseConfig, dto.getParams(), page);
+            if (dto.getIsTrans()) {
+                // 关联数据显示转换
+                FormDataTransUtil.transData(pageData.getList(), formDesignConfig);
+            }
+            return pageData;
+        } else {
+            throw new MyException("主表不存在");
+        }
+    }
+
+    @Override
+    public PageOutput<Entity> appPage(AppFormExecutePageDto dto) {
+        AppFuncDesign funcDesign = appFuncDesignService.getById(dto.getFuncId());
+//        FormRelease formRelease = formReleaseMapper.selectById(dto.getReleaseId());
+
+        String configJson = funcDesign.getJsonContent();
+        //发布配置
+        FormReleaseConfig formReleaseConfig = JSONUtil.toBean(configJson, FormReleaseConfig.class);
+
+        //自定义表单配置
+        FormDesignConfig formDesignConfig = JSONUtil.toBean(configJson, FormDesignConfig.class);
+
+        List<TableConfig> tableConfigs = formDesignConfig.getTableConfigs();
+        //主表
+        Optional<TableConfig> mainTable = tableConfigs.stream().filter(TableConfig::getIsMain).findFirst();
+
+        if (mainTable.isPresent()) {
+            TableConfig tableConfig = mainTable.get();
+            String tableName = tableConfig.getTableName();
+
+            //构建分页参数
+            Page page = new Page(dto.getLimit() - 1, dto.getSize());
+            String field = dto.getField();
+            String orderStr = dto.getOrder();
+            ListConfig listConfig = formReleaseConfig.getListConfig();
+            if (StrUtil.isBlank(field)) {
+                field = StrUtil.emptyToDefault(listConfig.getOrderBy(), tableConfig.getPkField());
+                orderStr = StrUtil.emptyToDefault(listConfig.getOrderType(), "desc");
+            }
+            if (StrUtil.isNotBlank(field)) {
+                Order order = new Order();
+                order.setDirection(StrUtil.equalsIgnoreCase(orderStr, "desc") ? Direction.DESC : Direction.ASC);
+                order.setField(field);
+                page.setOrder(order);
+            }
+
+            List<ColumnConfig> columnConfigs = listConfig.getColumnConfigs();
+            Set<String> fieldsList = columnConfigs.stream().map(ColumnConfig::getColumnName).collect(Collectors.toSet());
+            // 添加权限所属人字段返回
+            if (BooleanUtils.isTrue(formDesignConfig.getIsDataAuth())) {
+                fieldsList.add(GlobalConstant.AUTH_USER_ID);
+            }
+
+            PageOutput<Entity> pageData = getPageDataByExpression(tableName, fieldsList, formDesignConfig, formReleaseConfig, dto.getParams(), page);
+            if (dto.getIsTrans()) {
+                // 关联数据显示转换
+                FormDataTransUtil.transData(pageData.getList(), formDesignConfig);
+            }
+            return pageData;
+        } else {
+            throw new MyException("主表不存在");
+        }
+    }
+
+    @Override
+    public Object info(FormExecuteInfoDto dto) {
+        FormRelease formRelease = formReleaseMapper.selectById(dto.getReleaseId());
+
+        String configJson = formRelease.getConfigJson();
+
+        //发布配置
+        FormReleaseConfig formReleaseConfig = JSONUtil.toBean(configJson, FormReleaseConfig.class);
+
+        //自定义表单数据
+        FormTemplate template = formTemplateMapper.selectById(formRelease.getFormId());
+
+        String formJson = template.getFormJson();
+        //自定义表单配置
+        FormDesignConfig formDesignConfig = JSONUtil.toBean(formJson, FormDesignConfig.class);
+        //表关系配置
+        List<TableConfig> tableConfigs = formDesignConfig.getTableConfigs();
+        //主表
+        Optional<TableConfig> mainTable = tableConfigs.stream().filter(TableConfig::getIsMain).findFirst();
+
+        if (mainTable.isPresent()) {
+            TableConfig tableConfig = mainTable.get();
+            String tableName = tableConfig.getTableName();
+
+            Map<String, List<ComponentConfig>> formComponentListMap = GeneratorUtil.buildFormComponentList(formDesignConfig.getFormJson().getList());
+            List<String> fieldsList = new ArrayList<>();
+            for (ComponentConfig config : formComponentListMap.get(tableName)) {
+                String type = config.getType();
+                if (StrUtil.equalsIgnoreCase(type, ComponentTypeConstant.TIME_RANGE) || StrUtil.equalsIgnoreCase(type, ComponentTypeConstant.DATE_RANGE)) {
+                    fieldsList.add(config.getBindStartTime());
+                    fieldsList.add(config.getBindEndTime());
+                } else {
+                    fieldsList.add(config.getBindField());
+                }
+            }
+
+            return getFormData(tableName, fieldsList, formDesignConfig, dto.getId());
+        } else {
+            throw new MyException("主表不存在");
+        }
+
+    }
+
+    @Override
+    public Object appInfo(AppFormExecuteInfoDto dto) {
+        AppFuncDesign funcDesign = appFuncDesignService.getById(dto.getFuncId());
+//        FormRelease formRelease = formReleaseMapper.selectById(dto.getReleaseId());
+
+        String configJson = funcDesign.getJsonContent();
+
+        //自定义表单配置
+        FormDesignConfig formDesignConfig = JSONUtil.toBean(configJson, FormDesignConfig.class);
+        //表关系配置
+        List<TableConfig> tableConfigs = formDesignConfig.getTableConfigs();
+        //主表
+        Optional<TableConfig> mainTable = tableConfigs.stream().filter(TableConfig::getIsMain).findFirst();
+
+        if (mainTable.isPresent()) {
+            TableConfig tableConfig = mainTable.get();
+            String tableName = tableConfig.getTableName();
+
+            Map<String, List<ComponentConfig>> formComponentListMap = GeneratorUtil.buildFormComponentList(formDesignConfig.getFormJson().getList());
+            List<String> fieldsList = new ArrayList<>();
+            for (ComponentConfig config : formComponentListMap.get(tableName)) {
+                String type = config.getType();
+                if (StrUtil.equalsIgnoreCase(type, ComponentTypeConstant.TIME_RANGE) || StrUtil.equalsIgnoreCase(type, ComponentTypeConstant.DATE_RANGE)) {
+                    fieldsList.add(config.getBindStartTime());
+                    fieldsList.add(config.getBindEndTime());
+                } else {
+                    fieldsList.add(config.getBindField());
+                }
+            }
+
+            return getFormData(tableName, fieldsList, formDesignConfig, dto.getId());
+        } else {
+            throw new MyException("主表不存在");
+        }
+    }
+
+    @Override
+    public Boolean add(FormExecuteAddOrUpdateDto dto) {
+
+        FormRelease formRelease = formReleaseMapper.selectById(dto.getReleaseId());
+
+        Map<String, Object> formData = dto.getFormData();
+
+        String configJson = formRelease.getConfigJson();
+
+        //发布配置
+        FormReleaseConfig formReleaseConfig = JSONUtil.toBean(configJson, FormReleaseConfig.class);
+
+        //自定义表单数据
+        FormTemplate template = formTemplateMapper.selectById(formRelease.getFormId());
+
+        return insertFormData(formData, template);
+
+    }
+
+    @Override
+    public Boolean appAdd(AppFormExecuteAddOrUpdateDto dto) {
+        AppFuncDesign funcDesign = appFuncDesignService.getById(dto.getFuncId());
+
+        String configJson = funcDesign.getJsonContent();
+
+        Map<String, Object> formData = dto.getFormData();
+
+
+        //自定义表单数据
+        FormTemplate template = new FormTemplate();
+        template.setFormJson(configJson);
+
+        return insertFormData(formData, template);
+    }
+
+    public Boolean saveMainBatch(Long formTemplateId, List<Map<String, Object>> dataList) {
+        FormTemplate template = formTemplateMapper.selectById(formTemplateId);
+        String formJson = template.getFormJson();
+        //自定义表单配置
+        FormDesignConfig formDesignConfig = JSONUtil.toBean(formJson, FormDesignConfig.class);
+        //表关系配置
+        List<TableConfig> tableConfigs = formDesignConfig.getTableConfigs();
+        //主表
+        Optional<TableConfig> mainTable = tableConfigs.stream().filter(TableConfig::getIsMain).findFirst();
+        List<Entity> toSaveList = new ArrayList<>();
+        if (mainTable.isPresent()) {
+            String tableName = mainTable.get().getTableName();
+            //获取表里所有字段
+            DataSource datasource = DatasourceUtil.getDataSource(formDesignConfig.getDatabaseId());
+            Table tableMeta = MetaUtil.getTableMeta(datasource, tableName);
+            Collection<Column> columns = tableMeta.getColumns();
+            Optional<Column> pk = columns.stream().filter(Column::isPk).findFirst();
+
+            for (Map<String, Object> data : dataList) {
+                Entity where = Entity.create(tableName);
+                // 处理字段值
+                Map<String, Object> toSaveFormData = handleFormDataForSave(data, formDesignConfig, tableName, new ArrayList<>());
+
+                //formData 默认插入雪花Id主键
+                pk.ifPresent(column -> toSaveFormData.put(column.getName(), IdUtil.getSnowflakeNextId()));
+                where.putAll(toSaveFormData);
+                //如果有审计字段  默认填充值
+                putAuditEntityInsertData(where, columns);
+
+                toSaveList.add(where);
+            }
+            try {
+                Db.use(datasource).insert(toSaveList);
+                return true;
+            } catch (SQLException e) {
+                throw new MyException("批量新增数据失败!");
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public Boolean update(FormExecuteAddOrUpdateDto dto) {
+        FormRelease formRelease = formReleaseMapper.selectById(dto.getReleaseId());
+
+        String configJson = formRelease.getConfigJson();
+
+        Map<String, Object> formData = dto.getFormData();
+
+        //发布配置
+        FormReleaseConfig formReleaseConfig = JSONUtil.toBean(configJson, FormReleaseConfig.class);
+
+        //自定义表单数据
+        FormTemplate template = formTemplateMapper.selectById(formRelease.getFormId());
+
+        return updateFormData(formData, template);
+    }
+
+    @Override
+    public Boolean appUpdate(AppFormExecuteAddOrUpdateDto dto) {
+
+        AppFuncDesign funcDesign = appFuncDesignService.getById(dto.getFuncId());
+
+        String configJson = funcDesign.getJsonContent();
+
+        Map<String, Object> formData = dto.getFormData();
+
+
+        //自定义表单数据
+        FormTemplate template = new FormTemplate();
+        template.setFormJson(configJson);
+
+        return updateFormData(formData, template);
+    }
+
+
+    @Override
+    public Boolean delete(FormExecuteDeleteDto dto) {
+
+        FormRelease formRelease = formReleaseMapper.selectById(dto.getReleaseId());
+
+
+        String configJson = formRelease.getConfigJson();
+
+        //发布配置
+        FormReleaseConfig formReleaseConfig = JSONUtil.toBean(configJson, FormReleaseConfig.class);
+
+        //自定义表单数据
+        FormTemplate template = formTemplateMapper.selectById(formRelease.getFormId());
+
+        String formJson = template.getFormJson();
+        //自定义表单配置
+        FormDesignConfig formDesignConfig = JSONUtil.toBean(formJson, FormDesignConfig.class);
+        //表关系配置
+        List<TableConfig> tableConfigs = formDesignConfig.getTableConfigs();
+        //主表
+        Optional<TableConfig> mainTable = tableConfigs.stream().filter(TableConfig::getIsMain).findFirst();
+
+        if (mainTable.isPresent()) {
+            String tableName = mainTable.get().getTableName();
+
+            Entity entity = Entity.create(tableName);
+
+            DataSource datasource = DatasourceUtil.getDataSource(formDesignConfig.getDatabaseId());
+            //获取表里所有字段
+            Table tableMeta = MetaUtil.getTableMeta(datasource, tableName);
+            Collection<Column> columns = tableMeta.getColumns();
+            Optional<Column> pkOptinal = columns.stream().filter(Column::isPk).findFirst();
+            Column pk;
+            if (pkOptinal.isPresent()) {
+                pk = pkOptinal.get();
+            } else {
+                throw new MyException("主键不存在");
+            }
+
+
+            //获取所有需要删除的id
+            List<String> keyValues = dto.getIds();
+
+            //获取到所有子表
+            List<TableConfig> tableConfigList = tableConfigs.stream().filter(x -> !x.getIsMain()).collect(Collectors.toList());
+
+            Entity where = Entity.create(tableName);
+
+            if (StrUtil.equalsIgnoreCase(JdbcToJavaUtil.getClassName(pk), "Long")) {
+                where.set(pk.getName(), keyValues.stream().map(Long::parseLong).collect(Collectors.toList()));
+            } else {
+                where.set(pk.getName(), keyValues);
+            }
+
+            //如果有审计字段  默认填充值
+            putAuditEntityUpdateData(entity, columns);
+
+            //如果包含逻辑删除字段
+            if (columns.stream().anyMatch(x -> StrUtil.equalsIgnoreCase(GlobalConstant.DELETE_MARK, x.getName()))) {
+
+                Session session = Session.create(datasource);
+                try {
+                    session.beginTransaction();
+
+                    for (TableConfig tableConfig : tableConfigList) {
+
+                        Optional<TableConfig> childTableConfig = tableConfigList.stream().filter(x -> x.getTableName().equals(tableConfig.getTableName())).findFirst();
+
+                        if (childTableConfig.isPresent()) {
+
+                            List<Entity> entities = session.find(where);
+
+                            List<Object> allPkValue = entities.stream().map(x -> x.get(childTableConfig.get().getRelationTableField())).collect(Collectors.toList());
+
+                            //删除子表单数据
+                            Entity childDeleteWhere = Entity.create(tableConfig.getTableName()).
+                                    set(childTableConfig.get().getRelationField(), allPkValue);
+
+                            //没做子表单的软删除
+                            session.del(childDeleteWhere);
+
+                        }
+                    }
+
+                    // 更新主表数据
+                    entity.set(GlobalConstant.DELETE_MARK, DeleteMark.DELETED.getCode());
+                    session.update(entity, where);
+
+
+                    session.commit();
+                } catch (SQLException e) {
+                    session.quietRollback();
+                    throw new MyException("删除数据失败,数据回滚!");
+                }
+            } else {
+
+                Session session = Session.create(datasource);
+                try {
+                    session.beginTransaction();
+
+
+                    //删除子表数据
+                    for (TableConfig tableConfig : tableConfigList) {
+
+                        Optional<TableConfig> childTableConfig = tableConfigList.stream().filter(x -> x.getTableName().equals(tableConfig.getTableName())).findFirst();
+
+                        if (childTableConfig.isPresent()) {
+
+                            List<Entity> entities = session.find(where);
+
+                            List<Object> allPkValue = entities.stream().map(x -> x.get(childTableConfig.get().getRelationTableField())).collect(Collectors.toList());
+
+                            //删除子表单数据
+                            Entity childDeleteWhere = Entity.create(tableConfig.getTableName()).
+                                    set(childTableConfig.get().getRelationField(), allPkValue);
+
+                            //没做子表单的软删除
+                            session.del(childDeleteWhere);
+
+                        }
+                    }
+
+                    //删除主表数据
+                    session.del(where);
+
+
+                    session.commit();
+                } catch (SQLException e) {
+                    session.quietRollback();
+                    throw new MyException("删除数据失败,数据回滚!");
+                }
+            }
+
+            return true;
+        } else {
+            throw new MyException("主表不存在");
+        }
+    }
+
+    @Override
+    public Boolean appDelete(AppFormExecuteDeleteDto dto) {
+        AppFuncDesign funcDesign = appFuncDesignService.getById(dto.getFuncId());
+
+        String configJson = funcDesign.getJsonContent();
+
+        //自定义表单配置
+        FormDesignConfig formDesignConfig = JSONUtil.toBean(configJson, FormDesignConfig.class);
+        //表关系配置
+        List<TableConfig> tableConfigs = formDesignConfig.getTableConfigs();
+        //主表
+        Optional<TableConfig> mainTable = tableConfigs.stream().filter(TableConfig::getIsMain).findFirst();
+
+        if (mainTable.isPresent()) {
+            String tableName = mainTable.get().getTableName();
+
+            Entity entity = Entity.create(tableName);
+
+            DataSource datasource = DatasourceUtil.getDataSource(formDesignConfig.getDatabaseId());
+            //获取表里所有字段
+            Table tableMeta = MetaUtil.getTableMeta(datasource, tableName);
+            Collection<Column> columns = tableMeta.getColumns();
+            Optional<Column> pkOptinal = columns.stream().filter(Column::isPk).findFirst();
+            Column pk;
+            if (pkOptinal.isPresent()) {
+                pk = pkOptinal.get();
+            } else {
+                throw new MyException("主键不存在");
+            }
+
+
+            //获取所有需要删除的id
+            List<String> keyValues = dto.getIds();
+
+            //获取到所有子表
+            List<TableConfig> tableConfigList = tableConfigs.stream().filter(x -> !x.getIsMain()).collect(Collectors.toList());
+
+            Entity where = Entity.create(tableName);
+
+            where.set(pk.getName(), keyValues);
+
+            //如果有审计字段  默认填充值
+            putAuditEntityUpdateData(entity, columns);
+
+            //如果包含逻辑删除字段
+            if (columns.stream().anyMatch(x -> StrUtil.equalsIgnoreCase(GlobalConstant.DELETE_MARK, x.getName()))) {
+
+                Session session = Session.create(datasource);
+                try {
+                    session.beginTransaction();
+
+                    for (TableConfig tableConfig : tableConfigList) {
+
+                        Optional<TableConfig> childTableConfig = tableConfigList.stream().filter(x -> x.getTableName().equals(tableConfig.getTableName())).findFirst();
+
+                        if (childTableConfig.isPresent()) {
+
+                            List<Entity> entities = session.find(where);
+
+                            List<Object> allPkValue = entities.stream().map(x -> x.get(childTableConfig.get().getRelationTableField())).collect(Collectors.toList());
+
+                            //删除子表单数据
+                            Entity childDeleteWhere = Entity.create(tableConfig.getTableName()).
+                                    set(childTableConfig.get().getRelationField(), allPkValue);
+
+                            //没做子表单的软删除
+                            session.del(childDeleteWhere);
+
+                        }
+                    }
+
+                    // 更新主表数据
+                    entity.set(GlobalConstant.DELETE_MARK, DeleteMark.DELETED.getCode());
+                    session.update(entity, where);
+
+
+                    session.commit();
+                } catch (SQLException e) {
+                    session.quietRollback();
+                    throw new MyException("删除数据失败,数据回滚!");
+                }
+            } else {
+
+                Session session = Session.create(datasource);
+                try {
+                    session.beginTransaction();
+
+
+                    //删除子表数据
+                    for (TableConfig tableConfig : tableConfigList) {
+
+                        Optional<TableConfig> childTableConfig = tableConfigList.stream().filter(x -> x.getTableName().equals(tableConfig.getTableName())).findFirst();
+
+                        if (childTableConfig.isPresent()) {
+
+                            List<Entity> entities = session.find(where);
+
+                            List<Object> allPkValue = entities.stream().map(x -> x.get(childTableConfig.get().getRelationTableField())).collect(Collectors.toList());
+
+                            //删除子表单数据
+                            Entity childDeleteWhere = Entity.create(tableConfig.getTableName()).
+                                    set(childTableConfig.get().getRelationField(), allPkValue);
+
+                            //没做子表单的软删除
+                            session.del(childDeleteWhere);
+
+                        }
+                    }
+
+                    //删除主表数据
+                    session.del(where);
+
+
+                    session.commit();
+                } catch (SQLException e) {
+                    session.quietRollback();
+                    throw new MyException("删除数据失败,数据回滚!");
+                }
+            }
+
+            return true;
+        } else {
+            throw new MyException("主表不存在");
+        }
+    }
+
+    @Override
+    @SneakyThrows
+    public Triple<Session, Long, Long> workflowAdd(FormExecuteWorkflowAddDto dto) {
+        Map<String, Object> formData = dto.getFormData();
+        //自定义表单数据
+        FormTemplate template = formTemplateMapper.selectById(dto.formId);
+
+        return insertFormByWorkflow(formData, template);
+    }
+
+    @Override
+    public Triple<Session, Long, Long> workflowUpdate(FormExecuteWorkflowUpdateDto dto) {
+        Map<String, Object> formData = dto.getFormData();
+        //自定义表单数据
+        FormTemplate template = formTemplateMapper.selectById(dto.formId);
+
+        return updateFormDataByWorkflow(formData, template);
+    }
+
+    @Override
+    public Triple<Session, Boolean, Long> workflowAddOrUpdate(FormExecuteWorkflowUpdateDto dto) {
+        Map<String, Object> formData = dto.getFormData();
+        //自定义表单数据
+        FormTemplate template = formTemplateMapper.selectById(dto.formId);
+        return insertOrUpdateFormDataByWorkflow(formData, template);
+    }
+
+    @Override
+    public Object workFlowInfo(FormExecuteWorkflowInfoDto dto) {
+
+        //自定义表单数据
+        FormTemplate template = formTemplateMapper.selectById(dto.getFormId());
+
+        String formJson = template.getFormJson();
+        //自定义表单配置
+        FormDesignConfig formDesignConfig = JSONUtil.toBean(formJson, FormDesignConfig.class);
+        //表关系配置
+        List<TableConfig> tableConfigs = formDesignConfig.getTableConfigs();
+        //主表
+        Optional<TableConfig> mainTable = tableConfigs.stream().filter(TableConfig::getIsMain).findFirst();
+
+        if (mainTable.isPresent()) {
+            TableConfig tableConfig = mainTable.get();
+            String tableName = tableConfig.getTableName();
+
+            Optional<TableStructureConfig> mainConfig = formDesignConfig.getTableStructureConfigs().stream().filter(x -> x.getTableName().equals(tableName)).findFirst();
+
+            if (!mainConfig.isPresent()) {
+                throw new MyException("主表不存在");
+            }
+            List<String> fieldsList = mainConfig.get().getTableFieldConfigs().stream().map(TableFieldConfig::getFieldName).collect(Collectors.toList());
+
+            return getFormData(tableName, fieldsList, formDesignConfig, dto.getId().toString());
+        } else {
+            throw new MyException("主表不存在");
+        }
+    }
+
+
+    private boolean insertFormData(Map<String, Object> formData, FormTemplate template) {
+        String formJson = template.getFormJson();
+        //自定义表单配置
+        FormDesignConfig formDesignConfig = JSONUtil.toBean(formJson, FormDesignConfig.class);
+        //表关系配置
+        List<TableConfig> tableConfigs = formDesignConfig.getTableConfigs();
+        //主表
+        Optional<TableConfig> mainTable = tableConfigs.stream().filter(TableConfig::getIsMain).findFirst();
+
+        if (mainTable.isPresent()) {
+            String tableName = mainTable.get().getTableName();
+
+            Entity where = Entity.create(tableName);
+
+            DataSource datasource = DatasourceUtil.getDataSource(formDesignConfig.getDatabaseId());
+            //获取表里所有字段
+            Table tableMeta = MetaUtil.getTableMeta(datasource, tableName);
+            Collection<Column> columns = tableMeta.getColumns();
+            Optional<Column> pk = columns.stream().filter(Column::isPk).findFirst();
+
+            long keyValue = IdUtil.getSnowflakeNextId();
+
+            //遍历所有子表
+            List<TableConfig> tableConfigList = tableConfigs.stream().filter(x -> !x.getIsMain()).collect(Collectors.toList());
+
+            //所有子表数据
+            Map<String, List<Entity>> childMaps = new HashMap<>(tableConfigList.size());
+            // 自动编码code
+            List<String> autoCodeList = new ArrayList<>();
+            // 处理字段值
+            Map<String, Object> toSaveFormData = handleFormDataForSave(formData, formDesignConfig, tableName, autoCodeList);
+
+            //formData 默认插入雪花Id主键
+            if (pk.isPresent()) {
+                formData.put(pk.get().getName(), keyValue);
+                toSaveFormData.put(pk.get().getName(), keyValue);
+            }
+
+            //构建子表单数据
+            wrapperChildEntity(datasource, tableConfigList, childMaps, formData, formDesignConfig, keyValue, autoCodeList);
+
+
+            //此时的formData 已经是剔除了子表单数据了
+            where.putAll(toSaveFormData);
+            //如果有审计字段  默认填充值
+            putAuditEntityInsertData(where, columns);
+
+            Session session = Session.create(datasource);
+            try {
+                session.beginTransaction();
+                // 保存主表数据
+                session.insert(where);
+                // 保存子表数据
+                for (Map.Entry<String, List<Entity>> tableMap : childMaps.entrySet()) {
+                    List<Entity> childList = tableMap.getValue();
+                    session.insert(childList);
+                }
+                codeRuleService.useEncode(autoCodeList);
+                session.commit();
+            } catch (SQLException e) {
+                session.quietRollback();
+                throw new MyException("新增数据失败,数据回滚!", e);
+            }
+
+            return true;
+        } else {
+            throw new MyException("主表不存在");
+        }
+    }
+
+    private boolean updateFormData(Map<String, Object> formData, FormTemplate template) {
+        String formJson = template.getFormJson();
+        //自定义表单配置
+        FormDesignConfig formDesignConfig = JSONUtil.toBean(formJson, FormDesignConfig.class);
+        //表关系配置
+        List<TableConfig> tableConfigs = formDesignConfig.getTableConfigs();
+        //主表
+        Optional<TableConfig> mainTable = tableConfigs.stream().filter(TableConfig::getIsMain).findFirst();
+
+        if (mainTable.isPresent()) {
+            String tableName = mainTable.get().getTableName();
+
+            Entity entity = Entity.create(tableName);
+
+            DataSource datasource = DatasourceUtil.getDataSource(formDesignConfig.getDatabaseId());
+            //获取表里所有字段
+            Table tableMeta = MetaUtil.getTableMeta(datasource, tableName);
+            Collection<Column> columns = tableMeta.getColumns();
+            Optional<Column> pkOptional = columns.stream().filter(Column::isPk).findFirst();
+            Column pk;
+            if (pkOptional.isPresent()) {
+                pk = pkOptional.get();
+            } else {
+                throw new MyException("主键不存在");
+            }
+
+
+            //遍历所有子表
+            List<TableConfig> tableConfigList = tableConfigs.stream().filter(x -> !x.getIsMain()).collect(Collectors.toList());
+
+            //所有子表数据
+            Map<String, List<Entity>> childMaps = new HashMap<>(tableConfigList.size());
+
+            //更新的时候默认使用string 的key  因为客户的表 可能什么类型的主键都有  所以默认使用string
+            String keyValue = MapUtil.get(formData, pk.getName(), String.class);
+
+
+            Object keyValue2 = null;
+            if (StrUtil.equalsIgnoreCase(JdbcToJavaUtil.getClassName(pk), "Long")) {
+                keyValue2 = Long.valueOf(keyValue);
+            } else {
+                keyValue2 = keyValue;
+            }
+            //where 拼接 id
+            Entity where = Entity.create(tableName).set(pk.getName(), keyValue2);
+
+            //构建子表单数据
+            wrapperChildEntity(datasource, tableConfigList, childMaps, formData, formDesignConfig, keyValue2, null);
+
+            // 处理字段值
+            formData = handleFormDataForSave(formData, formDesignConfig, tableName, null);
+
+            //此时的formData 已经是剔除了子表单数据了
+            entity.putAll(formData);
+
+            //主表如果有审计字段  默认填充值
+            putAuditEntityUpdateData(entity, columns);
+
+            Session session = Session.create(datasource);
+            try {
+                session.beginTransaction();
+                // 更新主表数据
+                session.update(entity, where);
+
+
+                // 遍历数据 根据 表名 保存子表数据
+                for (Map.Entry<String, List<Entity>> tableMap : childMaps.entrySet()) {
+                    //先删除子表单数据 然后再新增  这里使用物理删除  不再逻辑删除。  tableMap的key  就是 子表的表名
+                    Optional<TableConfig> childTableConfig = tableConfigList.stream().filter(x -> x.getTableName().equals(tableMap.getKey())).findFirst();
+
+                    if (childTableConfig.isPresent()) {
+                        //删除子表单数据
+                        Entity childDeleteWhere = Entity.create(tableMap.getKey()).set(childTableConfig.get().getRelationField(), keyValue2);
+                        session.del(childDeleteWhere);
+
+                        //再重新新增
+                        List<Entity> childList = tableMap.getValue();
+                        session.insert(childList);
+                    }
+
+                }
+                session.commit();
+            } catch (SQLException e) {
+                session.quietRollback();
+                throw new MyException("修改数据失败,数据回滚!", e);
+            }
+
+            return true;
+        } else {
+            throw new MyException("主表不存在");
+        }
+    }
+
+    @SneakyThrows
+    private Triple<Session, Long, Long> insertFormByWorkflow(Map<String, Object> formData, FormTemplate template) {
+
+        String formJson = template.getFormJson();
+        //自定义表单配置
+        FormDesignConfig formDesignConfig = JSONUtil.toBean(formJson, FormDesignConfig.class);
+        //表关系配置
+        List<TableConfig> tableConfigs = formDesignConfig.getTableConfigs();
+        //主表
+        Optional<TableConfig> mainTable = tableConfigs.stream().filter(TableConfig::getIsMain).findFirst();
+
+        if (mainTable.isPresent()) {
+            String tableName = mainTable.get().getTableName();
+
+            Entity where = Entity.create(tableName);
+
+            DataSource datasource = DatasourceUtil.getDataSource(formDesignConfig.getDatabaseId());
+            //获取表里所有字段
+            Table tableMeta = MetaUtil.getTableMeta(datasource, tableName);
+            Collection<Column> columns = tableMeta.getColumns();
+            Optional<Column> pk = columns.stream().filter(Column::isPk).findFirst();
+
+            long keyValue = IdUtil.getSnowflakeNextId();
+
+            //遍历所有子表
+            List<TableConfig> tableConfigList = tableConfigs.stream().filter(x -> !x.getIsMain()).collect(Collectors.toList());
+
+            //所有子表数据
+            Map<String, List<Entity>> childMaps = new HashMap<>(tableConfigList.size());
+
+            // 自动编码code
+            List<String> autoCodeList = new ArrayList<>();
+
+            //构建子表单数据
+            //深拷贝一份表单数据 避免修改原表单数据
+            Map<String, Object> newFormData = ObjectUtil.cloneIfPossible(formData);
+            Map<String, List<Map<String, Object>>> childFormData = wrapperChildEntity(datasource, tableConfigList, childMaps, newFormData, formDesignConfig, keyValue, autoCodeList);
+
+            // 处理字段值
+            newFormData = handleFormDataForSave(newFormData, formDesignConfig, tableName, autoCodeList);
+
+            //formData 默认插入雪花Id主键
+            if (pk.isPresent()) {
+                newFormData.put(pk.get().getName(), keyValue);
+            }
+
+            //此时的formData 已经是剔除了子表单数据了
+            where.putAll(newFormData);
+
+            //如果有审计字段  默认填充值
+            putAuditEntityInsertData(where, columns);
+
+            Session session = Session.create(datasource);
+            session.beginTransaction();
+            // 保存主表数据
+            session.insert(where);
+            // 保存子表数据
+            for (Map.Entry<String, List<Entity>> tableMap : childMaps.entrySet()) {
+                List<Entity> childList = tableMap.getValue();
+                session.insert(childList);
+                //工作流调用自定义表单方法 添加数据 必须需要这一行代码 构建之后的子表单数据 覆盖原formData 数据
+                formData.put(tableMap.getKey() + "List", childFormData.get(tableMap.getKey()));
+            }
+            // 使用自动编码
+            codeRuleService.useEncode(autoCodeList);
+
+            //返回值元组,  用于多返回值  left 为当前session middle 为formId  right为当前主表主键
+            return new ImmutableTriple<>(session, template.getId(), keyValue);
+        } else {
+            throw new MyException("主表不存在");
+        }
+    }
+
+    @SneakyThrows
+    private Triple<Session, Long, Long> updateFormDataByWorkflow(Map<String, Object> formData, FormTemplate template) {
+        String formJson = template.getFormJson();
+        //自定义表单配置
+        FormDesignConfig formDesignConfig = JSONUtil.toBean(formJson, FormDesignConfig.class);
+        //表关系配置
+        List<TableConfig> tableConfigs = formDesignConfig.getTableConfigs();
+        //主表
+        Optional<TableConfig> mainTable = tableConfigs.stream().filter(TableConfig::getIsMain).findFirst();
+
+        if (mainTable.isPresent()) {
+            String tableName = mainTable.get().getTableName();
+
+            Entity entity = Entity.create(tableName);
+
+            DataSource datasource = DatasourceUtil.getDataSource(formDesignConfig.getDatabaseId());
+            //获取表里所有字段
+            Table tableMeta = MetaUtil.getTableMeta(datasource, tableName);
+            Collection<Column> columns = tableMeta.getColumns();
+            Optional<Column> pkOptional = columns.stream().filter(Column::isPk).findFirst();
+            Column pk;
+            if (pkOptional.isPresent()) {
+                pk = pkOptional.get();
+            } else {
+                throw new MyException("主键不存在");
+            }
+
+
+            //遍历所有子表
+            List<TableConfig> tableConfigList = tableConfigs.stream().filter(x -> !x.getIsMain()).collect(Collectors.toList());
+
+            //所有子表数据
+            Map<String, List<Entity>> childMaps = new HashMap<>(tableConfigList.size());
+
+            //更新的时候默认使用string 的key  因为客户的表 可能什么类型的主键都有  所以默认使用string
+            //TODO 可能会出现各种类型的主键 目前是建议客户使用Long类型主键
+            Long keyValue = MapUtil.get(formData, pk.getName(), Long.class);
+
+            //where 拼接 id
+            Entity where = Entity.create(tableName);
+
+            //构建子表单数据
+            //深拷贝一份表单数据 避免修改原表单数据
+            Map<String, Object> newFormData = ObjectUtil.cloneIfPossible(formData);
+            Map<String, List<Map<String, Object>>> childFormData = wrapperChildEntity(datasource, tableConfigList, childMaps, newFormData, formDesignConfig, keyValue, null);
+
+            // 处理字段值
+            newFormData = handleFormDataForSave(newFormData, formDesignConfig, tableName, null);
+
+            //此时的formData 已经是剔除了子表单数据了
+            newFormData.remove(pk.getName());
+            entity.putAll(newFormData);
+
+            //主表如果有审计字段  默认填充值
+            putAuditEntityUpdateData(entity, columns);
+
+            Session session = Session.create(datasource);
+            session.beginTransaction();
+
+            if (pk.getTypeName().equals("varchar")) { //常用主键为String类型,默认为Long类型
+                where = where.set(pk.getName(), keyValue.toString());
+            } else {
+                where = where.set(pk.getName(), keyValue);
+            }
+            // 更新主表数据
+            session.update(entity, where);
+
+            // 遍历数据 根据 表名 保存子表数据
+            for (Map.Entry<String, List<Entity>> tableMap : childMaps.entrySet()) {
+                //先删除子表单数据 然后再新增  这里使用物理删除  不再逻辑删除。  tableMap的key  就是 子表的表名
+                Optional<TableConfig> childTableConfig = tableConfigList.stream().filter(x -> x.getTableName().equals(tableMap.getKey())).findFirst();
+
+                if (childTableConfig.isPresent()) {
+                    //删除子表单数据
+                    Entity childDeleteWhere = Entity.create(tableMap.getKey()).set(childTableConfig.get().getRelationField(), keyValue);
+                    session.del(childDeleteWhere);
+
+                    //再重新新增
+                    List<Entity> childList = tableMap.getValue();
+                    session.insert(childList);
+
+                    //工作流调用自定义表单方法 必须需要这一行代码 构建之后的子表单数据 覆盖原formData 数据
+                    formData.put(tableMap.getKey() + "List", childFormData.get(tableMap.getKey()));
+                }
+
+            }
+            return new ImmutableTriple<>(session, template.getId(), keyValue);
+        } else {
+            throw new MyException("主表不存在");
+        }
+    }
+
+    @SneakyThrows
+    private Triple<Session, Boolean, Long> insertOrUpdateFormDataByWorkflow(Map<String, Object> formData, FormTemplate template) {
+        String formJson = template.getFormJson();
+        //自定义表单配置
+        FormDesignConfig formDesignConfig = JSONUtil.toBean(formJson, FormDesignConfig.class);
+        //表关系配置
+        List<TableConfig> tableConfigs = formDesignConfig.getTableConfigs();
+        //主表
+        Optional<TableConfig> mainTable = tableConfigs.stream().filter(TableConfig::getIsMain).findFirst();
+
+        if (mainTable.isPresent()) {
+            String tableName = mainTable.get().getTableName();
+
+            Entity entity = Entity.create(tableName);
+
+            DataSource datasource = DatasourceUtil.getDataSource(formDesignConfig.getDatabaseId());
+            //获取表里所有字段
+            Table tableMeta = MetaUtil.getTableMeta(datasource, tableName);
+            Collection<Column> columns = tableMeta.getColumns();
+            Optional<Column> pkOptional = columns.stream().filter(Column::isPk).findFirst();
+            Column pk;
+            if (pkOptional.isPresent()) {
+                pk = pkOptional.get();
+            } else {
+                throw new MyException("主键不存在");
+            }
+
+
+            //遍历所有子表
+            List<TableConfig> tableConfigList = tableConfigs.stream().filter(x -> !x.getIsMain()).collect(Collectors.toList());
+
+            //所有子表数据
+            Map<String, List<Entity>> childMaps = new HashMap<>(tableConfigList.size());
+
+            //更新的时候默认使用string 的key  因为客户的表 可能什么类型的主键都有  所以默认使用string
+            //TODO 可能会出现各种类型的主键 目前是建议客户使用Long类型主键
+            Long keyValue = MapUtil.get(formData, pk.getName(), Long.class);
+
+            //如果不为空就是更新
+            if (ObjectUtil.isNotNull(keyValue)) {
+                //where 拼接 id
+                Entity where = Entity.create(tableName).set(pk.getName(), keyValue);
+
+
+                //构建子表单数据
+                //深拷贝一份表单数据 避免修改原表单数据
+                Map<String, Object> newFormData = ObjectUtil.cloneIfPossible(formData);
+                Map<String, List<Map<String, Object>>> childFormData = wrapperChildEntity(datasource, tableConfigList, childMaps, newFormData, formDesignConfig, keyValue, null);
+
+                // 处理字段值
+                Map<String, Object> toSaveFormData = handleFormDataForSave(newFormData, formDesignConfig, tableName, null);
+                //此时的formData 已经是剔除了子表单数据了
+                toSaveFormData.remove(pk.getName());
+                entity.putAll(toSaveFormData);
+
+                //主表如果有审计字段  默认填充值
+                putAuditEntityUpdateData(entity, columns);
+
+                Session session = Session.create(datasource);
+                session.beginTransaction();
+                // 更新主表数据
+                session.update(entity, where);
+
+                // 遍历数据 根据 表名 保存子表数据
+                for (Map.Entry<String, List<Entity>> tableMap : childMaps.entrySet()) {
+                    //先删除子表单数据 然后再新增  这里使用物理删除  不再逻辑删除。  tableMap的key  就是 子表的表名
+                    Optional<TableConfig> childTableConfig = tableConfigList.stream().filter(x -> x.getTableName().equals(tableMap.getKey())).findFirst();
+
+                    if (childTableConfig.isPresent()) {
+                        //删除子表单数据
+                        Entity childDeleteWhere = Entity.create(tableMap.getKey()).set(childTableConfig.get().getRelationField(), keyValue);
+                        session.del(childDeleteWhere);
+
+                        //再重新新增
+                        List<Entity> childList = tableMap.getValue();
+                        session.insert(childList);
+
+                        //工作流调用自定义表单方法 必须需要这一行代码 构建之后的子表单数据 覆盖原formData 数据
+                        formData.put(tableMap.getKey() + "List", childFormData.get(tableMap.getKey()));
+                    }
+
+                }
+                //返回值元组,  用于多返回值  left 为当前session middle 为false 代表新增 为true 代表更新  right为当前主表主键
+                return new ImmutableTriple<>(session, true, keyValue);
+            }
+            //新增
+            else {
+                Entity where = Entity.create(tableName);
+                //formData 默认插入雪花Id主键
+                keyValue = IdUtil.getSnowflakeNextId();
+
+                //构建子表单数据
+                //深拷贝一份表单数据 避免修改原表单数据
+                Map<String, Object> newFormData = ObjectUtil.cloneIfPossible(formData);
+
+                if (ObjectUtil.isNull(newFormData)) {
+                    newFormData = new HashMap<>();
+                }
+                // 自动编码code
+                List<String> autoCodeList = new ArrayList<>();
+                Map<String, List<Map<String, Object>>> childFormData = wrapperChildEntity(datasource, tableConfigList, childMaps, newFormData, formDesignConfig, keyValue, autoCodeList);
+
+                // 处理字段值
+                Map<String, Object> toSaveFormData = handleFormDataForSave(newFormData, formDesignConfig, tableName, autoCodeList);
+                toSaveFormData.put(pk.getName(), keyValue);
+                formData.put(pk.getName(), keyValue);
+                //此时的formData 已经是剔除了子表单数据了
+                where.putAll(toSaveFormData);
+
+                //如果有审计字段  默认填充值
+                putAuditEntityInsertData(where, columns);
+
+                Session session = Session.create(datasource);
+                session.beginTransaction();
+                // 保存主表数据
+                session.insert(where);
+                // 保存子表数据
+                for (Map.Entry<String, List<Entity>> tableMap : childMaps.entrySet()) {
+                    List<Entity> childList = tableMap.getValue();
+                    session.insert(childList);
+                    //工作流调用自定义表单方法 添加数据 必须需要这一行代码 构建之后的子表单数据 覆盖原formData 数据
+                    formData.put(tableMap.getKey() + "List", childFormData.get(tableMap.getKey()));
+                }
+                codeRuleService.useEncode(autoCodeList);
+                //返回值元组,  用于多返回值  left 为当前session middle 为false 代表新增 为true 代表更新  right为当前主表主键
+                return new ImmutableTriple<>(session, false, keyValue);
+            }
+
+
+        } else {
+            throw new MyException("主表不存在");
+        }
+    }
+
+    /**
+     * 根据配置信息获取不分页列表数据
+     *
+     * @param tableName         主表名
+     * @param fieldsList        列表所有字段名
+     * @param formDesignConfig  表单配置
+     * @param formReleaseConfig 表单发布配置
+     * @param params            入参
+     * @return 列表数据
+     */
+    @SneakyThrows
+    private List<Entity> getListDataByExpression(String tableName, List<String> fieldsList, FormDesignConfig formDesignConfig, FormReleaseConfig formReleaseConfig, Map<String, Object> params) {
+        DataSource datasource = DatasourceUtil.getDataSource(formDesignConfig.getDatabaseId());
+
+        //获取表里所有字段
+        Table tableMeta = MetaUtil.getTableMeta(datasource, tableName);
+        Collection<Column> columns = tableMeta.getColumns();
+        Optional<Column> pkOptional = columns.stream().filter(Column::isPk).findFirst();
+        Column pkColumn;
+
+        if (pkOptional.isPresent()) {
+            pkColumn = pkOptional.get();
+            fieldsList.add(0, pkColumn.getName());
+        } else {
+            throw new MyException("主键不存在");
+        }
+
+        List<net.sf.jsqlparser.schema.Column> jsqlColumn = new ArrayList<>();
+        for (String field : fieldsList) {
+            jsqlColumn.add(new net.sf.jsqlparser.schema.Column(field));
+        }
+        Select select = SelectUtils.buildSelectFromTableAndExpressions(new net.sf.jsqlparser.schema.Table(tableName), jsqlColumn.toArray(new net.sf.jsqlparser.schema.Column[0]));
+        PlainSelect plainSelect = (PlainSelect) select.getSelectBody(); // 转换为更细化的Select对象
+
+        List<QueryConfig> queryConfigs = formReleaseConfig.getListConfig().getQueryConfigs();
+
+        //如果有左侧树 需要把所选项目 where 条件加上
+        if (formReleaseConfig.getListConfig().getIsLeftMenu()) {
+            //如果已经包含此字段  就不添加了
+            if (queryConfigs.stream().noneMatch(x -> StrUtil.equals(x.getFieldName(), formReleaseConfig.getListConfig().getLeftMenuConfig().getListFieldName()))) {
+                QueryConfig queryConfig = new QueryConfig();
+                queryConfig.setFieldName(formReleaseConfig.getListConfig().getLeftMenuConfig().getListFieldName());
+                queryConfig.setIsDate(false);
+                queryConfigs.add(queryConfig);
+            }
+
+        }
+        Expression queryExpression = null;
+
+        //遍历所有查询条件
+        for (QueryConfig queryConfig : queryConfigs) {
+
+            //如果是日期类型 默认设置查询参数为两个
+            if (queryConfig.getIsDate()) {
+                //根据查询配置的字段名 从参数里面找到对应的值  如果是时间类型 需要查询start 和 end
+                String startTime = MapUtil.get(params, queryConfig.getFieldName() + GlobalConstant.START_TIME_SUFFIX, String.class);
+                String endTime = MapUtil.get(params, queryConfig.getFieldName() + GlobalConstant.END_TIME_SUFFIX, String.class);
+
+                //如果全都没有数据 则跳过
+                if (startTime == null && endTime == null) {
+                    continue;
+                }
+
+                if (startTime != null) {
+                    GreaterThanEquals geq = new GreaterThanEquals(); // ">="
+                    geq.setLeftExpression(new net.sf.jsqlparser.schema.Column(queryConfig.getFieldName() + GlobalConstant.START_TIME_SUFFIX));
+                    geq.setRightExpression(new StringValue(startTime));
+
+                    //如果是第一个条件 直接赋值
+                    if (ObjectUtil.isNull(queryExpression)) {
+                        queryExpression = geq;
+                    } else {
+                        queryExpression = new AndExpression(queryExpression, geq);
+                    }
+                }
+
+                if (endTime != null) {
+                    MinorThanEquals leq = new MinorThanEquals();// "<="
+                    leq.setLeftExpression(new net.sf.jsqlparser.schema.Column(queryConfig.getFieldName() + GlobalConstant.END_TIME_SUFFIX));
+                    leq.setRightExpression(new StringValue(endTime));
+
+                    //如果是第一个条件 直接赋值
+                    if (ObjectUtil.isNull(queryExpression)) {
+                        queryExpression = leq;
+                    } else {
+                        queryExpression = new AndExpression(queryExpression, leq);
+                    }
+                }
+
+            } else {
+
+                Object value = MapUtil.get(params, queryConfig.getFieldName(), Object.class);
+                //如果没有数据 则跳过
+                if (value == null || StrUtil.isEmpty(String.valueOf(value))) {
+                    continue;
+                }
+
+                //因为前端传入过来的key  默认都是驼峰命名  但是数据库里面的字段是下划线命名  需要转换一下 再判断是否存在
+                Optional<Column> columnOptional = columns.stream().filter(column -> StrUtil.equalsIgnoreCase(column.getName(), queryConfig.getFieldName())).findFirst();
+
+                if (!columnOptional.isPresent()) {
+                    continue;
+                }
+
+                String className = JdbcToJavaUtil.getClassName(columnOptional.get());
+
+                if (LIKE_CLASS_NAME.contains(className)) {
+
+                    LikeExpression likeExpression = new LikeExpression(); // 创建Like表达式对象
+                    likeExpression.setLeftExpression(new net.sf.jsqlparser.schema.Column(queryConfig.getFieldName()));
+                    likeExpression.setRightExpression(new StringValue(StringPool.PERCENT + value + StringPool.PERCENT));
+
+                    //如果是第一个条件 直接赋值
+                    if (ObjectUtil.isNull(queryExpression)) {
+                        queryExpression = likeExpression;
+                    } else {
+                        queryExpression = new AndExpression(queryExpression, likeExpression);
+                    }
+
+                }
+
+                if (EQ_CLASS_NAME.contains(className)) {
+                    EqualsTo eq = new EqualsTo();
+                    eq.setLeftExpression(new net.sf.jsqlparser.schema.Column(queryConfig.getFieldName()));
+                    eq.setRightExpression(new StringValue(String.valueOf(value)));
+
+                    //如果是第一个条件 直接赋值
+                    if (ObjectUtil.isNull(queryExpression)) {
+                        queryExpression = eq;
+                    } else {
+                        queryExpression = new AndExpression(queryExpression, eq);
+                    }
+                }
+
+                if (TIME_CLASS_NAME.contains(className)) {
+                    //根据查询配置的字段名 从参数里面找到对应的值  如果是时间类型 需要查询start 和 end
+                    String startTime = MapUtil.get(params, queryConfig.getFieldName() + GlobalConstant.START_TIME_SUFFIX, String.class);
+                    String endTime = MapUtil.get(params, queryConfig.getFieldName() + GlobalConstant.END_TIME_SUFFIX, String.class);
+
+                    if (startTime != null) {
+                        GreaterThanEquals geq = new GreaterThanEquals(); // ">="
+                        geq.setLeftExpression(new net.sf.jsqlparser.schema.Column(queryConfig.getFieldName() + GlobalConstant.START_TIME_SUFFIX));
+                        geq.setRightExpression(new StringValue(startTime));
+
+                        //如果是第一个条件 直接赋值
+                        if (ObjectUtil.isNull(queryExpression)) {
+                            queryExpression = geq;
+                        } else {
+                            queryExpression = new AndExpression(queryExpression, geq);
+                        }
+                    }
+
+                    if (endTime != null) {
+                        MinorThanEquals leq = new MinorThanEquals();// "<="
+                        leq.setLeftExpression(new net.sf.jsqlparser.schema.Column(queryConfig.getFieldName() + GlobalConstant.END_TIME_SUFFIX));
+                        leq.setRightExpression(new StringValue(endTime));
+
+                        //如果是第一个条件 直接赋值
+                        if (ObjectUtil.isNull(queryExpression)) {
+                            queryExpression = leq;
+                        } else {
+                            queryExpression = new AndExpression(queryExpression, leq);
+                        }
+                    }
+                }
+
+            }
+        }
+
+        //判断是否存在删除标记字段  如果带有删除标记字段则进行删除标记字段的判断
+        if (columns.stream().anyMatch(column -> StrUtil.equalsIgnoreCase(GlobalConstant.DELETE_MARK, column.getName()))) {
+            EqualsTo eq = new EqualsTo();
+            eq.setLeftExpression(new net.sf.jsqlparser.schema.Column(GlobalConstant.DELETE_MARK));
+            eq.setRightExpression(new LongValue(DeleteMark.NODELETE.getCode()));
+
+            //如果是第一个条件 直接赋值
+            if (ObjectUtil.isNull(queryExpression)) {
+                queryExpression = eq;
+            } else {
+                queryExpression = new AndExpression(queryExpression, eq);
+            }
+        }
+
+
+        Expression dataAuthExpression = AuthorityUtil.getDataAuthExpressionByTableName(tableName, null);
+
+        if (ObjectUtil.isNotNull(dataAuthExpression)) {
+            if (queryExpression == null) {
+                queryExpression = dataAuthExpression;
+            } else {
+                queryExpression = new AndExpression(queryExpression, dataAuthExpression);
+            }
+        }
+        plainSelect.setWhere(queryExpression);
+
+        //将所有查询的数据id 转string
+        List<Entity> entities = DbUtil.use(datasource).query(plainSelect.toString());
+
+        for (Entity entity : entities) {
+            entity.set(pkColumn.getName(), entity.get(pkColumn.getName()).toString());
+        }
+        return entities;
+    }
+
+
+    /**
+     * 根据配置信息获取不分页列表数据
+     *
+     * @param tableName         主表名
+     * @param fieldsList        列表所有字段名
+     * @param formDesignConfig  表单配置
+     * @param formReleaseConfig 表单发布配置
+     * @param params            入参
+     * @return 列表数据
+     */
+    @SneakyThrows
+    private List<Entity> getListData(String tableName, List<String> fieldsList, FormDesignConfig formDesignConfig, FormReleaseConfig formReleaseConfig, Map<String, Object> params) {
+        DataSource datasource = DatasourceUtil.getDataSource(formDesignConfig.getDatabaseId());
+
+        //获取表里所有字段
+        Table tableMeta = MetaUtil.getTableMeta(datasource, tableName);
+        Collection<Column> columns = tableMeta.getColumns();
+        Optional<Column> pkOptional = columns.stream().filter(Column::isPk).findFirst();
+        Column pkColumn;
+
+        if (pkOptional.isPresent()) {
+            pkColumn = pkOptional.get();
+            fieldsList.add(0, pkColumn.getName());
+        } else {
+            throw new MyException("主键不存在");
+        }
+
+        Entity where = Entity.create(tableName).setFieldNames(fieldsList);
+
+        List<QueryConfig> queryConfigs = formReleaseConfig.getListConfig().getQueryConfigs();
+
+
+        //如果有左侧树 需要把所选项目 where 条件加上
+        if (formReleaseConfig.getListConfig().getIsLeftMenu()) {
+            //如果已经包含此字段  就不添加了
+            if (queryConfigs.stream().noneMatch(x -> StrUtil.equals(x.getFieldName(), formReleaseConfig.getListConfig().getLeftMenuConfig().getListFieldName()))) {
+                QueryConfig queryConfig = new QueryConfig();
+                queryConfig.setFieldName(formReleaseConfig.getListConfig().getLeftMenuConfig().getListFieldName());
+                queryConfig.setIsDate(false);
+                queryConfigs.add(queryConfig);
+            }
+
+        }
+
+        //遍历所有查询条件
+        for (QueryConfig queryConfig : queryConfigs) {
+
+            //如果是日期类型 默认设置查询参数为两个
+            if (queryConfig.getIsDate()) {
+                //根据查询配置的字段名 从参数里面找到对应的值  如果是时间类型 需要查询start 和 end
+                wrapperDateQuery(params, where, queryConfig);
+
+            } else {
+
+                Object value = params.get(queryConfig.getFieldName());
+                //如果没有数据 则跳过
+                if (value == null || StrUtil.isEmpty(String.valueOf(value))) {
+                    continue;
+                }
+
+                //因为前端传入过来的key  默认都是驼峰命名  但是数据库里面的字段是下划线命名  需要转换一下 再判断是否存在
+                Optional<Column> columnOptional = columns.stream().filter(column -> StrUtil.equalsIgnoreCase(StringUtils.underlineToCamel(column.getName()), queryConfig.getFieldName())).findFirst();
+
+                //如果有这个字段 判断是属于什么java类型  然后设置查询参数
+                columnOptional.ifPresent(column -> {
+                    String className = JdbcToJavaUtil.getClassName(column);
+
+                    wrapperPageQueryCondition(params, where, queryConfig, value, className);
+
+                });
+
+
+            }
+        }
+
+        //判断是否存在删除标记字段  如果带有删除标记字段则进行删除标记字段的判断
+        if (columns.stream().anyMatch(column -> StrUtil.equalsIgnoreCase(GlobalConstant.DELETE_MARK, column.getName()))) {
+            where.set(GlobalConstant.DELETE_MARK, DeleteMark.NODELETE.getCode());
+        }
+
+        //将所有查询的数据id 转string
+        List<Entity> entities = Db.use(datasource).find(where);
+
+        for (Entity entity : entities) {
+            entity.set(pkColumn.getName(), entity.get(pkColumn.getName()).toString());
+        }
+        return entities;
+    }
+
+    /**
+     * 根据配置信息获取分页列表数据
+     *
+     * @param tableName         主表名
+     * @param fieldsList        列表所有字段名
+     * @param formDesignConfig  表单配置
+     * @param formReleaseConfig 表单发布配置
+     * @param params            入参
+     * @param page              分页参数
+     * @return 列表数据
+     */
+    @SneakyThrows
+    private PageOutput<Entity> getPageDataByExpression(String tableName, Set<String> fieldsList, FormDesignConfig formDesignConfig, FormReleaseConfig formReleaseConfig, Map<String, Object> params, Page page) {
+        DataSource datasource = DatasourceUtil.getDataSource(formDesignConfig.getDatabaseId());
+        //获取表里所有字段
+        Table tableMeta = MetaUtil.getTableMeta(datasource, tableName);
+        Collection<Column> columns = tableMeta.getColumns();
+
+        Optional<Column> pkOptional = columns.stream().filter(Column::isPk).findFirst();
+        Column pkColumn;
+
+        if (pkOptional.isPresent()) {
+            pkColumn = pkOptional.get();
+            fieldsList.add(pkColumn.getName());
+        } else {
+            throw new MyException("主键不存在");
+        }
+
+
+        List<net.sf.jsqlparser.schema.Column> jsqlColumn = new ArrayList<>();
+        for (String field : fieldsList) {
+            jsqlColumn.add(new net.sf.jsqlparser.schema.Column(field));
+        }
+        Select select = SelectUtils.buildSelectFromTableAndExpressions(new net.sf.jsqlparser.schema.Table(tableName), jsqlColumn.toArray(new net.sf.jsqlparser.schema.Column[0]));
+        PlainSelect plainSelect = (PlainSelect) select.getSelectBody(); // 转换为更细化的Select对象
+
+        List<QueryConfig> queryConfigs = formReleaseConfig.getListConfig().getQueryConfigs();
+
+        //如果有左侧树 需要把所选项目 where 条件加上
+        if (formReleaseConfig.getListConfig().getIsLeftMenu()) {
+            //如果已经包含此字段  就不添加了
+            if (queryConfigs.stream().noneMatch(x -> StrUtil.equals(x.getFieldName(), formReleaseConfig.getListConfig().getLeftMenuConfig().getListFieldName()))) {
+                QueryConfig queryConfig = new QueryConfig();
+                queryConfig.setFieldName(formReleaseConfig.getListConfig().getLeftMenuConfig().getListFieldName());
+                queryConfig.setIsDate(false);
+                queryConfigs.add(queryConfig);
+            }
+
+        }
+        Expression queryExpression = null;
+
+        //遍历所有查询条件
+        for (QueryConfig queryConfig : queryConfigs) {
+            String fieldName = queryConfig.getFieldName();
+            //如果是日期类型 默认设置查询参数为两个
+            if (queryConfig.getIsDate()) {
+                //根据查询配置的字段名 从参数里面找到对应的值  如果是时间类型 需要查询start 和 end
+                String startTime = MapUtil.get(params, fieldName + GlobalConstant.START_TIME_SUFFIX, String.class);
+                String endTime = MapUtil.get(params, fieldName + GlobalConstant.END_TIME_SUFFIX, String.class);
+
+                //如果全都没有数据 则跳过
+                if (startTime == null && endTime == null) {
+                    continue;
+                }
+                Expression startRightExp = null;
+                Expression endRightExp = null;
+                Column queryColumn = columns.stream().filter(c -> StrUtil.equalsIgnoreCase(c.getName(), fieldName)).findFirst().get();
+                JdbcType type = queryColumn.getTypeEnum();
+                if (type == JdbcType.TIME) {
+                    if (StrUtil.isNotEmpty(startTime)) startRightExp = new StringValue(startTime);
+                    if (StrUtil.isNotEmpty(endTime)) endRightExp = new StringValue(endTime);
+                } else if (type == JdbcType.DATE || type == JdbcType.TIMESTAMP) {
+                    if (StrUtil.isNotEmpty(startTime))
+                        startRightExp = new TimestampValue().withValue(Timestamp.valueOf(LocalDateTimeUtil.parseDateByLength(startTime)));
+                    if (StrUtil.isNotEmpty(endTime))
+                        endRightExp = new TimestampValue().withValue(Timestamp.valueOf(LocalDateTimeUtil.parseDateByLength(endTime)));
+                } else if (StrUtil.equalsIgnoreCase(queryColumn.getTypeName(), OracleFieldsType.TIME.getType())) {
+                    // oracle时间字段处理
+                    if (StrUtil.isNotEmpty(startTime))
+                        startRightExp = new StringValue(StringPool.ZERO + StringPool.SPACE + startTime);
+                    if (StrUtil.isNotEmpty(endTime))
+                        endRightExp = new StringValue(StringPool.ZERO + StringPool.SPACE + endTime);
+                }
+                if (startTime != null) {
+                    GreaterThanEquals geq = new GreaterThanEquals(); // ">="
+                    geq.setLeftExpression(new net.sf.jsqlparser.schema.Column(fieldName));
+                    geq.setRightExpression(startRightExp == null ? new StringValue(startTime) : startRightExp);
+
+                    //如果是第一个条件 直接赋值
+                    if (ObjectUtil.isNull(queryExpression)) {
+                        queryExpression = geq;
+                    } else {
+                        queryExpression = new AndExpression(queryExpression, geq);
+                    }
+                }
+
+                if (endTime != null) {
+                    MinorThanEquals leq = new MinorThanEquals();// "<="
+                    leq.setLeftExpression(new net.sf.jsqlparser.schema.Column(fieldName));
+                    leq.setRightExpression(endRightExp == null ? new StringValue(endTime) : endRightExp);
+
+                    //如果是第一个条件 直接赋值
+                    if (ObjectUtil.isNull(queryExpression)) {
+                        queryExpression = leq;
+                    } else {
+                        queryExpression = new AndExpression(queryExpression, leq);
+                    }
+                }
+
+            } else {
+
+                Object value = MapUtil.get(params, fieldName, Object.class);
+                //如果没有数据 则跳过
+                if (value == null || StrUtil.isEmpty(String.valueOf(value))) {
+                    continue;
+                }
+
+                //因为前端传入过来的key  默认都是驼峰命名  但是数据库里面的字段是下划线命名  需要转换一下 再判断是否存在
+                Optional<Column> columnOptional = columns.stream().filter(column -> StrUtil.equalsIgnoreCase(column.getName(), fieldName)).findFirst();
+
+                if (!columnOptional.isPresent()) {
+                    continue;
+                }
+
+                String className = JdbcToJavaUtil.getClassName(columnOptional.get());
+
+                if (LIKE_CLASS_NAME.contains(className)) {
+
+                    LikeExpression likeExpression = new LikeExpression(); // 创建Like表达式对象
+                    likeExpression.setLeftExpression(new net.sf.jsqlparser.schema.Column(fieldName));
+                    likeExpression.setRightExpression(new StringValue(StringPool.PERCENT + value + StringPool.PERCENT));
+
+                    //如果是第一个条件 直接赋值
+                    if (ObjectUtil.isNull(queryExpression)) {
+                        queryExpression = likeExpression;
+                    } else {
+                        queryExpression = new AndExpression(queryExpression, likeExpression);
+                    }
+
+                }
+
+                if (EQ_CLASS_NAME.contains(className)) {
+                    EqualsTo eq = new EqualsTo();
+                    eq.setLeftExpression(new net.sf.jsqlparser.schema.Column(fieldName));
+                    eq.setRightExpression(new StringValue(String.valueOf(value)));
+
+                    //如果是第一个条件 直接赋值
+                    if (ObjectUtil.isNull(queryExpression)) {
+                        queryExpression = eq;
+                    } else {
+                        queryExpression = new AndExpression(queryExpression, eq);
+                    }
+                }
+
+                if (TIME_CLASS_NAME.contains(className)) {
+                    //根据查询配置的字段名 从参数里面找到对应的值  如果是时间类型 需要查询start 和 end
+                    String startTime = MapUtil.get(params, fieldName + GlobalConstant.START_TIME_SUFFIX, String.class);
+                    String endTime = MapUtil.get(params, fieldName + GlobalConstant.END_TIME_SUFFIX, String.class);
+
+                    if (startTime != null) {
+                        GreaterThanEquals geq = new GreaterThanEquals(); // ">="
+                        geq.setLeftExpression(new net.sf.jsqlparser.schema.Column(fieldName + GlobalConstant.START_TIME_SUFFIX));
+                        geq.setRightExpression(new StringValue(startTime));
+
+                        //如果是第一个条件 直接赋值
+                        if (ObjectUtil.isNull(queryExpression)) {
+                            queryExpression = geq;
+                        } else {
+                            queryExpression = new AndExpression(queryExpression, geq);
+                        }
+                    }
+
+                    if (endTime != null) {
+                        MinorThanEquals leq = new MinorThanEquals();// "<="
+                        leq.setLeftExpression(new net.sf.jsqlparser.schema.Column(fieldName + GlobalConstant.END_TIME_SUFFIX));
+                        leq.setRightExpression(new StringValue(endTime));
+
+                        //如果是第一个条件 直接赋值
+                        if (ObjectUtil.isNull(queryExpression)) {
+                            queryExpression = leq;
+                        } else {
+                            queryExpression = new AndExpression(queryExpression, leq);
+                        }
+                    }
+                }
+
+            }
+        }
+
+        //判断是否存在删除标记字段  如果带有删除标记字段则进行删除标记字段的判断
+        if (columns.stream().anyMatch(column -> StrUtil.equalsIgnoreCase(GlobalConstant.DELETE_MARK, column.getName()))) {
+            EqualsTo eq = new EqualsTo();
+            eq.setLeftExpression(new net.sf.jsqlparser.schema.Column(GlobalConstant.DELETE_MARK));
+            eq.setRightExpression(new LongValue(DeleteMark.NODELETE.getCode()));
+
+            //如果是第一个条件 直接赋值
+            if (ObjectUtil.isNull(queryExpression)) {
+                queryExpression = eq;
+            } else {
+                queryExpression = new AndExpression(queryExpression, eq);
+            }
+        }
+
+
+        Expression dataAuthExpression = AuthorityUtil.getDataAuthExpressionByTableName(tableName, null);
+
+        if (ObjectUtil.isNotNull(dataAuthExpression)) {
+            if (queryExpression == null) {
+                queryExpression = dataAuthExpression;
+            } else {
+                queryExpression = new AndExpression(queryExpression, dataAuthExpression);
+            }
+        }
+        plainSelect.setWhere(queryExpression);
+        Db use = Db.use(datasource);
+        use.setRunner(new XjrSqlConnRunner(DialectFactory.getDialect(datasource)));
+        PageResult<Entity> pageResult = use.page(plainSelect.toString(), page);
+
+        //将所有查询的数据id 转string
+        for (Entity entity : pageResult) {
+            entity.set(pkColumn.getName(), entity.get(pkColumn.getName()).toString());
+        }
+
+        PageOutput<Entity> pageOutput = new PageOutput<>();
+        pageOutput.setPageSize(pageResult.getPageSize());
+        pageOutput.setCurrentPage(pageResult.getPage());
+        pageOutput.setTotal(pageResult.getTotal());
+        pageOutput.setList(pageResult);
+
+        return pageOutput;
+    }
+
+    /**
+     * 根据配置信息获取分页列表数据
+     *
+     * @param tableName         主表名
+     * @param fieldsList        列表所有字段名
+     * @param formDesignConfig  表单配置
+     * @param formReleaseConfig 表单发布配置
+     * @param params            入参
+     * @param page              分页参数
+     * @return 列表数据
+     */
+    @SneakyThrows
+    private PageOutput<Entity> getPageData(String tableName, List<String> fieldsList, FormDesignConfig formDesignConfig, FormReleaseConfig formReleaseConfig, Map<String, Object> params, Page page) {
+        DataSource datasource = DatasourceUtil.getDataSource(formDesignConfig.getDatabaseId());
+        //获取表里所有字段
+        Table tableMeta = MetaUtil.getTableMeta(datasource, tableName);
+        Collection<Column> columns = tableMeta.getColumns();
+
+        Optional<Column> pkOptional = columns.stream().filter(Column::isPk).findFirst();
+        Column pkColumn;
+
+        if (pkOptional.isPresent()) {
+            pkColumn = pkOptional.get();
+            fieldsList.add(0, pkColumn.getName());
+        } else {
+            throw new MyException("主键不存在");
+        }
+        Entity where = Entity.create(tableName).setFieldNames(fieldsList);
+
+        List<QueryConfig> queryConfigs = formReleaseConfig.getListConfig().getQueryConfigs();
+
+        //如果有左侧树 需要把所选项目 where 条件加上
+        if (formReleaseConfig.getListConfig().getIsLeftMenu()) {
+            //如果已经包含此字段  就不添加了
+            if (queryConfigs.stream().noneMatch(x -> StrUtil.equals(x.getFieldName(), formReleaseConfig.getListConfig().getLeftMenuConfig().getListFieldName()))) {
+                QueryConfig queryConfig = new QueryConfig();
+                queryConfig.setFieldName(formReleaseConfig.getListConfig().getLeftMenuConfig().getListFieldName());
+                queryConfig.setIsDate(false);
+                queryConfigs.add(queryConfig);
+            }
+
+        }
+
+        //遍历所有查询条件
+        for (QueryConfig queryConfig : queryConfigs) {
+
+            //如果是日期类型 默认设置查询参数为两个
+            if (queryConfig.getIsDate()) {
+                wrapperDateQuery(params, where, queryConfig);
+
+            } else {
+
+                Object value = params.get(queryConfig.getFieldName());
+                //如果没有数据 则跳过
+                if (value == null || StrUtil.isEmpty(String.valueOf(value))) {
+                    continue;
+                }
+
+                //因为前端传入过来的key  默认都是驼峰命名  但是数据库里面的字段是下划线命名  需要转换一下 再判断是否存在
+                Optional<Column> columnOptional = columns.stream().filter(column -> StrUtil.equalsIgnoreCase(column.getName(), queryConfig.getFieldName())).findFirst();
+
+                //如果有这个字段 判断是属于什么java类型  然后设置查询参数
+                columnOptional.ifPresent(column -> {
+                    String className = JdbcToJavaUtil.getClassName(column);
+
+                    wrapperPageQueryCondition(params, where, queryConfig, value, className);
+
+                });
+
+
+            }
+        }
+
+        //判断是否存在删除标记字段  如果带有删除标记字段则进行删除标记字段的判断
+        if (columns.stream().anyMatch(column -> StrUtil.equalsIgnoreCase(GlobalConstant.DELETE_MARK, column.getName()))) {
+            where.set(GlobalConstant.DELETE_MARK, DeleteMark.NODELETE.getCode());
+        }
+        PageResult<Entity> pageResult = Db.use(datasource).page(where, page);
+
+        //将所有查询的数据id 转string
+        for (Entity entity : pageResult) {
+            entity.set(pkColumn.getName(), entity.get(pkColumn.getName()).toString());
+        }
+        PageOutput<Entity> pageOutput = new PageOutput<>();
+        pageOutput.setPageSize(pageResult.getPageSize());
+        pageOutput.setCurrentPage(pageResult.getPage());
+        pageOutput.setTotal(pageResult.getTotal());
+        pageOutput.setList(pageResult);
+
+        return pageOutput;
+    }
+
+    /**
+     * 根据配置信息获取表单数据
+     *
+     * @param tableName        主表名
+     * @param fieldsList       列表所有字段名
+     * @param formDesignConfig 表单配置
+     * @param keyValue         主键
+     * @return 列表数据
+     */
+    @SneakyThrows
+    private Entity getFormData(String tableName, List<String> fieldsList, FormDesignConfig formDesignConfig, String keyValue) {
+        //获取表关系配置
+        List<TableConfig> tableConfigs = formDesignConfig.getTableConfigs();
+        //获取表结构配置 (因为要根据子表的字段配置 返回需要的数据)
+        List<TableStructureConfig> tableStructureConfigs = formDesignConfig.getTableStructureConfigs();
+
+        DataSource datasource = DatasourceUtil.getDataSource(formDesignConfig.getDatabaseId());
+
+
+        //获取表里所有字段
+        Table tableMeta = MetaUtil.getTableMeta(datasource, tableName);
+        Collection<Column> columns = tableMeta.getColumns();
+        Optional<Column> pk = columns.stream().filter(Column::isPk).findFirst();
+
+        if (!pk.isPresent()) {
+            throw new MyException("表" + tableName + "没有主键");
+        }
+        //把主键加入到查询项目
+        fieldsList.add(pk.get().getName());
+        Entity where = Entity.create(tableName).setFieldNames(fieldsList);
+        // 转行id类型
+        Object id = keyValue;
+        if (StrUtil.equalsIgnoreCase(JdbcToJavaUtil.getClassName(pk.get()), "Long")) {
+            id = Long.parseLong(keyValue);
+        }
+        where.set(pk.get().getName(), id);
+
+        //判断是否存在删除标记字段  如果带有删除标记字段则进行删除标记字段的判断
+        if (columns.stream().anyMatch(column -> StrUtil.equalsIgnoreCase(GlobalConstant.DELETE_MARK, column.getName()))) {
+            where.set(GlobalConstant.DELETE_MARK, DeleteMark.NODELETE.getCode());
+        }
+        GlobalDbConfig.setCaseInsensitive(false);
+        Entity formData = Db.use(datasource).find(where.getFieldNames(), where, new XjrEntityHandler());
+
+        //遍历所有子表
+        List<TableConfig> tableConfigList = tableConfigs.stream().filter(x -> !x.getIsMain()).collect(Collectors.toList());
+
+        for (TableConfig tableConfig : tableConfigList) {
+            Optional<TableStructureConfig> tableStructureConfigOptional = tableStructureConfigs.stream().filter(y -> StrUtil.equalsIgnoreCase(y.getTableName(), tableConfig.getTableName())).findFirst();
+            if (tableStructureConfigOptional.isPresent()) {
+                TableStructureConfig tableStructureConfig = tableStructureConfigOptional.get();
+                List<TableFieldConfig> tableFieldConfigs = tableStructureConfig.getTableFieldConfigs();
+                String childTableName = tableStructureConfig.getTableName();
+                List<String> childTableFields = tableFieldConfigs.stream().map(TableFieldConfig::getFieldName).collect(Collectors.toList());
+                Entity childWhere = Entity.create(childTableName).setFieldNames(childTableFields);
+
+                //获取子表关联主表的关联字段
+                Object parentValue = formData.get(tableConfig.getRelationTableField());
+                //默认新增条件 子表关联字段 = 主表的关联字段
+                childWhere.set(tableConfig.getRelationField(), parentValue);
+
+                //判断是否存在删除标记字段  如果带有删除标记字段则进行删除标记字段的判断
+                Table childTableMeta = MetaUtil.getTableMeta(datasource, childTableName);
+                Collection<Column> childColumns = childTableMeta.getColumns();
+
+                if (childColumns.stream().anyMatch(column -> StrUtil.equalsIgnoreCase(GlobalConstant.DELETE_MARK, column.getName()))) {
+                    childWhere.set(GlobalConstant.DELETE_MARK, DeleteMark.NODELETE.getCode());
+                }
+
+                List<Entity> childList = Db.use(datasource).find(childWhere, new XjrEntityListHandler());
+
+                formData.set(childTableName + "List", childList);
+            }
+        }
+
+        return formData;
+    }
+
+    /**
+     * 填充审计字段 新增
+     *
+     * @param entity
+     * @param columns
+     */
+    private void putAuditEntityInsertData(Entity entity, Collection<Column> columns) {
+        for (Column column : columns) {
+            if (StrUtil.equalsIgnoreCase(GlobalConstant.CREATE_USER_ID, column.getName())) {
+                entity.set(GlobalConstant.CREATE_USER_ID, StpUtil.getLoginIdAsLong());
+            }
+            if (StrUtil.equalsIgnoreCase(GlobalConstant.CREATE_DATE, column.getName())) {
+                entity.set(GlobalConstant.CREATE_DATE, Timestamp.valueOf(LocalDateTime.now()));
+            }
+            if (StrUtil.equalsIgnoreCase(GlobalConstant.DELETE_MARK, column.getName())) {
+                entity.set(GlobalConstant.DELETE_MARK, DeleteMark.NODELETE.getCode());
+            }
+            if (StrUtil.equalsIgnoreCase(GlobalConstant.ENABLED_MARK, column.getName())) {
+                entity.set(GlobalConstant.ENABLED_MARK, EnabledMark.ENABLED.getCode());
+            }
+            if (StrUtil.equalsIgnoreCase(GlobalConstant.AUTH_USER_ID, column.getName())) {
+                entity.set(GlobalConstant.AUTH_USER_ID, StpUtil.getLoginIdAsLong());
+            }
+        }
+    }
+
+    /**
+     * 填充审计字段 修改
+     *
+     * @param entity
+     * @param columns
+     */
+    private void putAuditEntityUpdateData(Entity entity, Collection<Column> columns) {
+        for (Column column : columns) {
+            if (StrUtil.equalsIgnoreCase(GlobalConstant.MODIFY_USER_ID, column.getName())) {
+                entity.set(GlobalConstant.MODIFY_USER_ID, StpUtil.getLoginIdAsLong());
+            }
+            if (StrUtil.equalsIgnoreCase(GlobalConstant.MODIFY_DATE, column.getName())) {
+                entity.set(GlobalConstant.MODIFY_DATE, Timestamp.valueOf(LocalDateTime.now()));
+            }
+        }
+    }
+
+    /**
+     * 新增数据时候 构建子表单Entity
+     *
+     * @param datasource
+     * @param tableConfigList
+     * @param childMaps
+     * @param formData
+     */
+    private Map<String, List<Map<String, Object>>> wrapperChildEntity(DataSource datasource, List<TableConfig> tableConfigList,
+                                                                      Map<String, List<Entity>> childMaps, Map<String, Object> formData,
+                                                                      FormDesignConfig formDesignConfig, Object keyValue, List<String> autoCodeList) {
+
+        Map<String, List<Map<String, Object>>> childFormData = new HashMap<>();
+
+        for (TableConfig tableConfig : tableConfigList) {
+
+            //获取表里所有字段
+            Table childTableMeta = MetaUtil.getTableMeta(datasource, tableConfig.getTableName());
+            Collection<Column> childColumns = childTableMeta.getColumns();
+
+            Optional<Column> childPkOptional = childColumns.stream().filter(Column::isPk).findFirst();
+
+            List<Map<String, Object>> childMap = new ArrayList<>();
+            List<Map<String, Object>> resultMap = new ArrayList<>();
+
+            Class<List<Map<String, Object>>> childMapClass = ClassUtil.getClass(childMap);
+            //获取子表的数据
+            childMap = MapUtil.get(formData, tableConfig.getTableName() + "List", childMapClass);
+
+            List<Entity> childEntities = new ArrayList<>();
+            for (Map<String, Object> stringObjectMap : childMap) {
+                Map<String, Object> handedMap = handleFormDataForSave(stringObjectMap, formDesignConfig, tableConfig.getTableName(), autoCodeList);
+                Entity entity = Entity.create(tableConfig.getTableName());
+                entity.putAll(handedMap);
+
+                //获取子表关联主表的关联字段
+                Object parentValue = formData.get(tableConfig.getRelationTableField());
+                //默认新增条件 子表关联字段 = 主表的关联字段
+                entity.set(tableConfig.getRelationField(), parentValue);
+
+                //填充子表主键
+                childPkOptional.ifPresent(pk -> {
+                    long snowflakeNextId = IdUtil.getSnowflakeNextId();
+                    entity.put(pk.getName(), snowflakeNextId);
+                    handedMap.put(pk.getName(), snowflakeNextId);
+
+                    if (ObjectUtil.isNotEmpty(keyValue)) {
+                        //将子表的parent_id,赋值为主表的主键值
+                        entity.put(tableConfig.getRelationField(), keyValue);
+                        handedMap.put(tableConfig.getRelationField(), keyValue);
+                    }
+                });
+                resultMap.add(handedMap);
+
+
+                //如果有审计字段  默认填充值
+                putAuditEntityInsertData(entity, childColumns);
+
+                childEntities.add(entity);
+            }
+
+            //获取到子表的所有数据
+            childMaps.put(tableConfig.getTableName(), childEntities);
+            childFormData.put(tableConfig.getTableName(), resultMap);
+
+            //移除Map中 子表的数据  避免sql错误;
+            MapUtil.removeAny(formData, tableConfig.getTableName() + "List");
+        }
+
+        return childFormData;
+    }
+
+
+    /**
+     * 分页查询时间  构建查询条件
+     *
+     * @param params
+     * @param where
+     * @param queryConfig
+     * @param value
+     * @param className
+     */
+    private void wrapperPageQueryCondition(Map<String, Object> params, Entity where, QueryConfig queryConfig, Object value, String className) {
+        if (LIKE_CLASS_NAME.contains(className)) {
+            where.set(queryConfig.getFieldName(), new Condition(queryConfig.getFieldName(), String.valueOf(value), Condition.LikeType.Contains));
+        }
+
+        if (EQ_CLASS_NAME.contains(className)) {
+            where.set(queryConfig.getFieldName(), new Condition(queryConfig.getFieldName(), String.valueOf(value), Condition.LikeType.Contains));
+        }
+
+        if (TIME_CLASS_NAME.contains(className)) {
+            //根据查询配置的字段名 从参数里面找到对应的值  如果是时间类型 需要查询start 和 end
+            Object startTime = params.get(queryConfig.getFieldName() + "Start");
+            Object endTime = params.get(queryConfig.getFieldName() + "End");
+
+            if (startTime != null) {
+                where.set(queryConfig.getFieldName() + "Start", new Condition(queryConfig.getFieldName(), ">=", startTime));
+            }
+
+            if (endTime != null) {
+                where.set(queryConfig.getFieldName() + "End", new Condition(queryConfig.getFieldName(), "<=", startTime));
+            }
+        }
+    }
+
+    /**
+     * 构建时间查询条件
+     *
+     * @param params
+     * @param where
+     * @param queryConfig
+     */
+    private void wrapperDateQuery(Map<String, Object> params, Entity where, QueryConfig queryConfig) {
+        //根据查询配置的字段名 从参数里面找到对应的值  如果是时间类型 需要查询start 和 end
+        Object startTime = params.get(queryConfig.getFieldName() + "Start");
+        Object endTime = params.get(queryConfig.getFieldName() + "End");
+
+        //如果全都没有数据 则跳过
+        if (startTime == null && endTime == null) {
+            return;
+        }
+
+        if (startTime != null) {
+            where.set(queryConfig.getFieldName() + "Start", new Condition(queryConfig.getFieldName(), ">=", startTime));
+        }
+
+        if (endTime != null) {
+            where.set(queryConfig.getFieldName() + "End", new Condition(queryConfig.getFieldName(), "<=", startTime));
+        }
+    }
+
+    /**
+     * 处理保存的表单数据
+     *
+     * @param formData
+     * @param formDesignConfig
+     */
+    private Map<String, Object> handleFormDataForSave(Map<String, Object> formData, FormDesignConfig formDesignConfig,
+                                                      String tableName, List<String> autoCodeList) {
+        Map<String, Object> resultData = new HashMap<>(formData.size());
+        Map<String, List<ComponentConfig>> componentListMap = GeneratorUtil.buildFormComponentList(formDesignConfig.getFormJson().getList());
+        List<ComponentConfig> configList = componentListMap.get(tableName);
+        Set<String> fieldNameList = formData.keySet();
+        DbType dbType = DatasourceUtil.getDbType(formDesignConfig.getDatabaseId());
+        for (ComponentConfig config : configList) {
+            Map<String, Object> options = config.getOptions();
+            if (MapUtils.getBoolean(options, "isSave", false)) {
+                continue;
+            }
+            String bindField = config.getBindField();
+            String bindStartTimeField = config.getBindStartTime();
+            String bindEndTimeField = config.getBindEndTime();
+            boolean isMatch = false;
+            for (String fieldName : fieldNameList) {
+                if (StrUtil.equalsIgnoreCase(fieldName, bindField)
+                        || StrUtil.equalsIgnoreCase(fieldName, bindStartTimeField)
+                        || StrUtil.equalsIgnoreCase(fieldName, bindEndTimeField)) {
+                    resultData.put(fieldName, formData.get(fieldName));
+                    isMatch = true;
+                }
+            }
+            if (!isMatch) continue;
+            String type = config.getType();
+            String format = MapUtils.getString(options, "format");
+            if (StrUtil.equalsIgnoreCase(type, ComponentTypeConstant.TIME)) {
+                Object timeObj = MapUtils.getObject(formData, bindField);
+                if (timeObj instanceof String) {
+                    resultData.put(bindField, LocalDateTimeUtil.parseDbTime(String.valueOf(timeObj), dbType));
+                } else if (timeObj instanceof LocalTime) {
+                    resultData.put(bindField, timeObj);
+                } else {
+                    resultData.put(bindField, null);
+                }
+            } else if (StrUtil.equalsIgnoreCase(type, ComponentTypeConstant.TIME_RANGE)) {
+                Object start = MapUtils.getObject(formData, bindStartTimeField);
+                Object end = MapUtils.getObject(formData, bindEndTimeField);
+                if (ObjectUtil.isNotEmpty(start)) {
+                    if (start instanceof String) {
+                        resultData.put(bindStartTimeField, LocalDateTimeUtil.parseDbTime(String.valueOf(start), dbType));
+                    } else {
+                        resultData.put(bindStartTimeField, start);
+                    }
+                } else {
+                    resultData.put(bindStartTimeField, null);
+                }
+                if (ObjectUtil.isNotEmpty(end)) {
+                    if (end instanceof String) {
+                        resultData.put(bindEndTimeField, LocalDateTimeUtil.parseDbTime(String.valueOf(end), dbType));
+                    } else {
+                        resultData.put(bindEndTimeField, end);
+                    }
+                } else {
+                    resultData.put(bindEndTimeField, null);
+                }
+            } else if (StrUtil.equalsIgnoreCase(type, ComponentTypeConstant.DATE)) {
+                Object valueStr = MapUtils.getObject(formData, bindField);
+                if (ObjectUtil.isNotEmpty(valueStr)) {
+                    resultData.put(bindField, valueStr instanceof LocalDateTime ? valueStr : DateTimeUtil.parseDate(LocalDateTimeUtil.parseDate(String.valueOf(valueStr), format).toString()));
+                } else {
+                    resultData.put(bindField, null);
+                }
+            } else if (StrUtil.equalsIgnoreCase(type, ComponentTypeConstant.DATE_RANGE)) {
+                Object start = MapUtils.getObject(formData, bindStartTimeField);
+                Object end = MapUtils.getObject(formData, bindEndTimeField);
+                if (ObjectUtil.isNotEmpty(start)) {
+                    resultData.put(bindStartTimeField, start instanceof LocalDateTime ? start : DateTimeUtil.parseDate(LocalDateTimeUtil.parseDate(String.valueOf(start), format).toString()));
+                } else {
+                    resultData.put(bindStartTimeField, null);
+                }
+                if (ObjectUtil.isNotEmpty(end)) {
+                    resultData.put(bindEndTimeField, end instanceof LocalDateTime ? end : DateTimeUtil.parseDate(LocalDateTimeUtil.parseDate(String.valueOf(end), format).toString()));
+                } else {
+                    resultData.put(bindEndTimeField, null);
+                }
+            } else if (StrUtil.equalsIgnoreCase(type, ComponentTypeConstant.AUTO_CODE)) {
+                if (autoCodeList != null)
+                    autoCodeList.add(MapUtils.getString(options, ComponentTypeConstant.AUTO_CODE_RULE));
+            }
+        }
+        return resultData;
+    }
+
+
+    public PageOutput<Entity> pageTrans(FormExecutePageDto dto) {
+
+        FormRelease formRelease = formReleaseMapper.selectById(dto.getReleaseId());
+
+
+        String configJson = formRelease.getConfigJson();
+
+        //发布配置
+        FormReleaseConfig formReleaseConfig = JSONUtil.toBean(configJson, FormReleaseConfig.class);
+
+        //自定义表单数据
+        FormTemplate template = formTemplateMapper.selectById(formRelease.getFormId());
+
+        String formJson = template.getFormJson();
+        //自定义表单配置
+        FormDesignConfig formDesignConfig = JSONUtil.toBean(formJson, FormDesignConfig.class);
+
+        List<TableConfig> tableConfigs = formDesignConfig.getTableConfigs();
+        //主表
+        Optional<TableConfig> mainTable = tableConfigs.stream().filter(TableConfig::getIsMain).findFirst();
+
+        if (mainTable.isPresent()) {
+            TableConfig tableConfig = mainTable.get();
+            String tableName = tableConfig.getTableName();
+
+            //构建分页参数
+            Page page = new Page(dto.getLimit() - 1, dto.getSize());
+            String field = dto.getField();
+            String orderStr = dto.getOrder();
+            ListConfig listConfig = formReleaseConfig.getListConfig();
+            if (StrUtil.isBlank(field)) {
+                field = StrUtil.emptyToDefault(listConfig.getOrderBy(), tableConfig.getPkField());
+                orderStr = StrUtil.emptyToDefault(listConfig.getOrderType(), "desc");
+            }
+            if (StrUtil.isNotBlank(field)) {
+                Order order = new Order();
+                order.setDirection(StrUtil.equalsIgnoreCase(orderStr, "desc") ? Direction.DESC : Direction.ASC);
+                order.setField(field);
+                page.setOrder(order);
+            }
+
+            List<ColumnConfig> columnConfigs = listConfig.getColumnConfigs();
+            Set<String> fieldsList = columnConfigs.stream().map(ColumnConfig::getColumnName).collect(Collectors.toSet());
+            // 添加权限所属人字段返回
+            if (BooleanUtils.isTrue(formDesignConfig.getIsDataAuth())) {
+                fieldsList.add(GlobalConstant.AUTH_USER_ID);
+            }
+
+            PageOutput<Entity> pageData = getPageDataByExpression(tableName, fieldsList, formDesignConfig, formReleaseConfig, dto.getParams(), page);
+            if (dto.getIsTrans()) {
+                // 关联数据显示转换
+                FormDataTransUtil.transDataOver(pageData.getList(), formDesignConfig);
+            }
+            return pageData;
+        } else {
+            throw new MyException("主表不存在");
+        }
+    }
+
+
+    @Override
+    public DeskTableInfoVo getTableInfo(Long formId) {
+        FormTemplate template = formTemplateMapper.selectById(formId);
+        String formJson = template.getFormJson();
+        //自定义表单配置
+        FormDesignConfig formDesignConfig = JSONUtil.toBean(formJson, FormDesignConfig.class);
+
+        List<TableConfig> tableConfigs = formDesignConfig.getTableConfigs();
+        //主表
+        Optional<TableConfig> mainTable = tableConfigs.stream().filter(TableConfig::getIsMain).findFirst();
+        DeskTableInfoVo deskTableInfoVo = new DeskTableInfoVo();
+        List<DeskColumnsVo> myColumnInfos = new ArrayList<>();
+        if (mainTable.isPresent()) {
+            TableConfig tableConfig = mainTable.get();
+            String tableName = tableConfig.getTableName();
+            //获取字段名
+            DataSource dataSource = DatasourceUtil.getDatasourceMaster();
+            Table tableMeta = MetaUtil.getTableMeta(dataSource, tableName);
+            Collection<Column> columns = tableMeta.getColumns();
+            Optional<Column> pk = columns.stream().filter(Column::isPk).findFirst();
+            if (!pk.isPresent()) {
+                throw new MyException("表" + tableName + "没有主键");
+            }
+            deskTableInfoVo.setPkName(pk.get().getName());
+            for (Column column : columns) {
+                DeskColumnsVo myColumnInfo = new DeskColumnsVo();
+                myColumnInfo.setLabel(column.getComment());
+                myColumnInfo.setProp(column.getName());
+                myColumnInfos.add(myColumnInfo);
+
+                DeskColumnsVo myColumnInfo1 = new DeskColumnsVo();
+                if (!column.getName().equals(pk.get().getName())) {
+                    myColumnInfo1.setLabel(column.getComment() + StringPool.UNDERSCORE + "接口");
+                    myColumnInfo1.setProp(column.getName() + StringPool.UNDERSCORE + "api");
+                    myColumnInfos.add(myColumnInfo1);
+                }
+
+            }
+            deskTableInfoVo.setDeskColumnsVoList(myColumnInfos);
+        } else {
+            throw new MyException("主表不存在");
+        }
+        return deskTableInfoVo;
+    }
+
+}

+ 4 - 17
src/main/java/com/xjrsoft/module/room/service/impl/RoomBedServiceImpl.java

@@ -263,38 +263,25 @@ public class RoomBedServiceImpl extends MPJBaseServiceImpl<RoomBedMapper, RoomBe
     @Override
     public Boolean distributeRoomBed(DistributeRoomBedDto dto) {
         List<Room> roomList = roomMapper.selectList(new QueryWrapper<Room>().lambda().in(Room::getId, dto.getRoomIds()));
-        Set<Integer> genderSet = new HashSet<>();
+        Set<String> genderSet = new HashSet<>();
         for (Room room : roomList) {
-            if("SB10001".equals(room.getGender())){
-                genderSet.add(1);
-            }else if("SB10002".equals(room.getGender())){
-                genderSet.add(2);
-            }
-        }
-        Map<Integer, String> genderMap = new HashMap<>();
-        for (Integer genderNumber : genderSet) {
-            if(genderNumber == 1){
-                genderMap.put(genderNumber, "SB10001");
-            }else if(genderNumber == 2){
-                genderMap.put(genderNumber, "SB10002");
-            }
+            genderSet.add(room.getGender());
         }
 
         Date modifyDate = new Date();
         Long modifyUserId = StpUtil.getLoginIdAsLong();
-
         //查询每个班的学生,修改床位信息
         int i = 0;
         Map<Long, Integer> classDistributeBedNumber = new HashMap<>();
         Map<Long, Integer> classStudent = new HashMap<>();
-        for (Integer genderNumber : genderSet) {
+        for (String genderNumber : genderSet) {
             //根据性别查询出所有空床位信息
             List<RoomBed> bedInfoList = roomBedMapper.selectList(
                 new MPJLambdaWrapper<RoomBed>()
                 .select(RoomBed::getId)
                 .select(RoomBed.class, x -> VoToColumnUtil.fieldsToColumns(RoomBed.class).contains(x.getProperty()))
                 .innerJoin(Room.class, Room::getId, RoomBed::getRoomId)
-                .eq(Room::getGender, genderMap.get(genderNumber))
+                .eq(Room::getGender, genderNumber)
                 .isNull(RoomBed::getStudentUserId)
                 .eq(RoomBed::getIsCheckIn, 0)
                 .in(RoomBed::getRoomId, dto.getRoomIds())

+ 1 - 1
src/main/java/com/xjrsoft/module/student/dto/UpdateBaseStudentUserDto.java

@@ -35,7 +35,7 @@ public class UpdateBaseStudentUserDto {
      * 性别
      */
     @ApiModelProperty("性别")
-    private Integer gender;
+    private String gender;
     /**
      * 手机号
      */

+ 21 - 95
src/main/java/com/xjrsoft/module/workflow/service/impl/WorkflowExecuteServiceImpl.java

@@ -24,17 +24,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 import com.github.yulichang.toolkit.MPJWrappers;
 import com.github.yulichang.wrapper.MPJLambdaWrapper;
 import com.xjrsoft.common.constant.GlobalConstant;
-import com.xjrsoft.common.enums.EnabledMark;
-import com.xjrsoft.common.enums.FormTemplateType;
-import com.xjrsoft.common.enums.WorkflowApproveType;
-import com.xjrsoft.common.enums.WorkflowAutoAgreeType;
-import com.xjrsoft.common.enums.WorkflowIsPrevChooseNextType;
-import com.xjrsoft.common.enums.WorkflowIsRecycleType;
-import com.xjrsoft.common.enums.WorkflowMultiInstanceFinishType;
-import com.xjrsoft.common.enums.WorkflowMultiInstanceType;
-import com.xjrsoft.common.enums.WorkflowNoHandlerType;
-import com.xjrsoft.common.enums.WorkflowRelationAuthType;
-import com.xjrsoft.common.enums.YesOrNoEnum;
+import com.xjrsoft.common.enums.*;
 import com.xjrsoft.common.exception.MyException;
 import com.xjrsoft.common.page.ConventPage;
 import com.xjrsoft.common.page.PageOutput;
@@ -82,12 +72,7 @@ import org.camunda.bpm.engine.HistoryService;
 import org.camunda.bpm.engine.RepositoryService;
 import org.camunda.bpm.engine.RuntimeService;
 import org.camunda.bpm.engine.TaskService;
-import org.camunda.bpm.engine.history.HistoricActivityInstance;
-import org.camunda.bpm.engine.history.HistoricProcessInstance;
-import org.camunda.bpm.engine.history.HistoricProcessInstanceQuery;
-import org.camunda.bpm.engine.history.HistoricTaskInstance;
-import org.camunda.bpm.engine.history.HistoricTaskInstanceQuery;
-import org.camunda.bpm.engine.history.HistoricVariableInstance;
+import org.camunda.bpm.engine.history.*;
 import org.camunda.bpm.engine.impl.persistence.entity.HistoricVariableInstanceEntity;
 import org.camunda.bpm.engine.impl.persistence.entity.TaskEntity;
 import org.camunda.bpm.engine.repository.Deployment;
@@ -109,19 +94,7 @@ import org.springframework.transaction.annotation.Transactional;
 import org.ssssssss.magicapi.core.service.MagicAPIService;
 
 import java.time.LocalDateTime;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
+import java.util.*;
 import java.util.stream.Collectors;
 
 /**
@@ -482,13 +455,13 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
             HistoricVariableInstance historicVariableInstance = historyService.createHistoricVariableInstanceQuery().processInstanceId(superProcessInstanceId).variableName(WorkflowConstant.PROCESS_SCHEMA_NAME_KEY).singleResult();
             //获取主流程审批记录
             List<ProcessRecordListVo> processRecordListVos = getProcessRecordListVos(superProcessInstanceId, 0);
-            // List<ProcessRecordListVo> processRecordListVos = getCustomProcessRecordListVos(superProcessInstanceId, 0);
 
             Map<String, Object> superProcessMap = new HashMap<>();
             superProcessMap.put("schemaName", historicVariableInstance.getValue() + "(上级流程)");
             superProcessMap.put("records", processRecordListVos);
 
             otherProcessApproveRecord.add(superProcessMap);
+
         }
 
         //查看当前流程 是否包含子流程
@@ -508,7 +481,6 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
 
                     //获取主流程审批记录
                     List<ProcessRecordListVo> processRecordListVos = getProcessRecordListVos(schemaNameVar.getProcessInstanceId(), 0);
-                    // List<ProcessRecordListVo> processRecordListVos = getCustomProcessRecordListVos(schemaNameVar.getProcessInstanceId(), 0);
                     superProcessMap.put("records", processRecordListVos);
 
                     otherProcessApproveRecord.add(superProcessMap);
@@ -518,7 +490,6 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
         //TODO  新增返回值  返回 主/子 流程 审批记录
 
         List<ProcessRecordListVo> recordListVos = getProcessRecordListVos(task.getProcessInstanceId(), 0);
-        // List<ProcessRecordListVo> recordListVos = getCustomProcessRecordListVos(task.getProcessInstanceId(), 0);
         vo.setTaskRecords(recordListVos);
         vo.setOtherProcessApproveRecord(otherProcessApproveRecord);
         return vo;
@@ -723,7 +694,6 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
                     HistoricVariableInstance historicVariableInstance = historyService.createHistoricVariableInstanceQuery().processInstanceId(superProcessInstanceId).variableName(WorkflowConstant.PROCESS_SCHEMA_NAME_KEY).singleResult();
                     //获取主流程审批记录
                     List<ProcessRecordListVo> processRecordListVos = getProcessRecordListVos(superProcessInstanceId, 0);
-                    // List<ProcessRecordListVo> processRecordListVos = getCustomProcessRecordListVos(superProcessInstanceId, 0);
 
                     Map<String, Object> superProcessMap = new HashMap<>();
                     superProcessMap.put("schemaName", historicVariableInstance.getValue() + "(上级流程)");
@@ -748,7 +718,6 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
 
                             //获取主流程审批记录
                             List<ProcessRecordListVo> processRecordListVos = getProcessRecordListVos(schemaNameVar.getProcessInstanceId(), 0);
-                            // List<ProcessRecordListVo> processRecordListVos = getCustomProcessRecordListVos(schemaNameVar.getProcessInstanceId(), 0);
                             superProcessMap.put("records", processRecordListVos);
 
                             otherProcessApproveRecord.add(superProcessMap);
@@ -758,7 +727,6 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
                 //TODO  新增返回值  返回 主/子 流程 审批记录
 
                 List<ProcessRecordListVo> recordListVos = getProcessRecordListVos(processId, 0);
-                // List<ProcessRecordListVo> recordListVos = getCustomProcessRecordListVos(processId, 0);
                 vo.setTaskRecords(recordListVos);
                 vo.setOtherProcessApproveRecord(otherProcessApproveRecord);
             }
@@ -845,7 +813,6 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
                     HistoricVariableInstance historicVariableInstance = historyService.createHistoricVariableInstanceQuery().processInstanceId(superProcessInstanceId).variableName(WorkflowConstant.PROCESS_SCHEMA_NAME_KEY).singleResult();
                     //获取主流程审批记录
                     List<ProcessRecordListVo> processRecordListVos = getProcessRecordListVos(superProcessInstanceId, 0);
-                    // List<ProcessRecordListVo> processRecordListVos = getCustomProcessRecordListVos(superProcessInstanceId, 0);
 
                     Map<String, Object> superProcessMap = new HashMap<>();
                     superProcessMap.put("schemaName", historicVariableInstance.getValue() + "(上级流程)");
@@ -870,7 +837,6 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
 
                             //获取主流程审批记录
                             List<ProcessRecordListVo> processRecordListVos = getProcessRecordListVos(schemaNameVar.getProcessInstanceId(), 0);
-                            // List<ProcessRecordListVo> processRecordListVos = getCustomProcessRecordListVos(schemaNameVar.getProcessInstanceId(), 0);
                             superProcessMap.put("records", processRecordListVos);
 
                             otherProcessApproveRecord.add(superProcessMap);
@@ -880,7 +846,6 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
                 //TODO  新增返回值  返回 主/子 流程 审批记录
 
                 List<ProcessRecordListVo> recordListVos = getProcessRecordListVos(processId, 0);
-                // List<ProcessRecordListVo> recordListVos = getCustomProcessRecordListVos(processId, 0);
                 vo.setTaskRecords(recordListVos);
                 vo.setOtherProcessApproveRecord(otherProcessApproveRecord);
             }
@@ -969,7 +934,6 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
                 HistoricVariableInstance historicVariableInstance = historyService.createHistoricVariableInstanceQuery().processInstanceId(superProcessInstanceId).variableName(WorkflowConstant.PROCESS_SCHEMA_NAME_KEY).singleResult();
                 //获取主流程审批记录
                 List<ProcessRecordListVo> processRecordListVos = getProcessRecordListVos(superProcessInstanceId, 0);
-                // List<ProcessRecordListVo> processRecordListVos = getCustomProcessRecordListVos(superProcessInstanceId, 0);
 
                 Map<String, Object> superProcessMap = new HashMap<>();
                 superProcessMap.put("schemaName", historicVariableInstance.getValue() + "(上级流程)");
@@ -994,7 +958,6 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
 
                         //获取主流程审批记录
                         List<ProcessRecordListVo> processRecordListVos = getProcessRecordListVos(schemaNameVar.getProcessInstanceId(), 0);
-                        // List<ProcessRecordListVo> processRecordListVos = getCustomProcessRecordListVos(schemaNameVar.getProcessInstanceId(), 0);
                         superProcessMap.put("records", processRecordListVos);
 
                         otherProcessApproveRecord.add(superProcessMap);
@@ -1004,7 +967,6 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
             //TODO  新增返回值  返回 主/子 流程 审批记录
 
             List<ProcessRecordListVo> recordListVos = getProcessRecordListVos(processId, 0);
-            // List<ProcessRecordListVo> recordListVos = getCustomProcessRecordListVos(processId, 0);
             vo.setTaskRecords(recordListVos);
             vo.setOtherProcessApproveRecord(otherProcessApproveRecord);
 
@@ -1031,7 +993,6 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
             HistoricVariableInstance historicVariableInstance = historyService.createHistoricVariableInstanceQuery().processInstanceId(superProcessInstanceId).variableName(WorkflowConstant.PROCESS_SCHEMA_NAME_KEY).singleResult();
             //获取主流程审批记录
             List<ProcessRecordListVo> processRecordListVos = getProcessRecordListVos(superProcessInstanceId, 1);
-            // List<ProcessRecordListVo> processRecordListVos = getCustomProcessRecordListVos(superProcessInstanceId, 1);
 
             Map<String, Object> superProcessMap = new HashMap<>();
             superProcessMap.put("schemaName", historicVariableInstance.getValue() + "(上级流程)");
@@ -1055,7 +1016,6 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
 
                     //获取主流程审批记录
                     List<ProcessRecordListVo> processRecordListVos = getProcessRecordListVos(schemaNameVar.getProcessInstanceId(), 1);
-                    // List<ProcessRecordListVo> processRecordListVos = getCustomProcessRecordListVos(schemaNameVar.getProcessInstanceId(), 1);
                     superProcessMap.put("records", processRecordListVos);
 
                     otherProcessApproveRecord.add(superProcessMap);
@@ -1065,7 +1025,6 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
         //TODO  新增返回值  返回 主/子 流程 审批记录
 
         List<ProcessRecordListVo> recordListVos = getProcessRecordListVos(processId, 1);
-        // List<ProcessRecordListVo> recordListVos = getCustomProcessRecordListVos(processId, 1);
         vo.setTaskRecords(recordListVos);
         vo.setOtherProcessApproveRecord(otherProcessApproveRecord);
         return vo;
@@ -1189,9 +1148,6 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
         //将map 转为 java类
         StartNodeConfig startNodeConfig = Convert.convert(StartNodeConfig.class, startNodeMap.get());
 
-        //定义sessionList  存储所有表提交的session  用于最后提交commit  保证事务
-        List<Session> sessionList = new ArrayList<>(dto.getFormData().size());
-
         //定义map 用于存储 formId以及 主键keyValue {formId:keyValue}
 //        Map<String, Long> keyValueMap = new HashMap<>(dto.getFormData().size());
 
@@ -1215,9 +1171,9 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
                 executeWorkflowUpdateDto.setFormData(thisFormData);
                 variableMap.putValue(formConfig.getKey(), thisFormData);
 
+                System.out.println("newLaunch start 0");
                 Triple<Session, Boolean, Long> sessionLongLongTriple = formExecuteService.workflowAddOrUpdate(executeWorkflowUpdateDto);
-
-                sessionList.add(sessionLongLongTriple.getLeft());
+                System.out.println("newLaunch start 1");
 
                 WorkflowFormRelation formRelation = new WorkflowFormRelation();
                 formRelation.setFormId(formConfig.getFormId());
@@ -1226,10 +1182,7 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
 
                 relations.add(formRelation);
             } catch (Exception e) {
-                log.error("提交表单数据失败(newLaunch):",e);
-                for (Session session : sessionList) {
-                    session.quietRollback();
-                }
+                log.error("提交表单数据失败(newLaunch):", e);
                 throw new MyException("【表单id: " + formConfig.getFormId() + "】 提交错误, 请联系管理员!");
             }
 
@@ -1244,39 +1197,31 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
         try {
             //表单提交完毕后 发起流程
             ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinition.getId(), variableMap);
-
+            System.out.println("newLaunch start 2");
             List<Task> list = taskService.createTaskQuery().processInstanceId(processInstance.getId()).list();
-
+            System.out.println("newLaunch start 3");
 //            List<LaunchAndApproveVo> result = isPrevChooseApprove(workflowSchemaConfig, list, variableMap);
 
             //如果不需要指定审批人 默认走自动同意规则
             invokeAutoAgree(processInstance.getId(), workflowSchema.getId(), workflowSchemaConfig, list);
-
+            System.out.println("newLaunch start 4");
             //重新获取任务节点,判断是否需要指定下一审批人
             list = taskService.createTaskQuery().processInstanceId(processInstance.getId()).list();
-
+            System.out.println("newLaunch start 5");
             List<LaunchAndApproveVo> result = isPrevChooseApprove(workflowSchemaConfig, list, variableMap);
-
+            System.out.println("newLaunch start 6");
             updateFileInfo(dto.getFileFolderIds(), processInstance.getId());
-
+            System.out.println("newLaunch start 7");
             //保存 流程 表单 关联 数据
             for (WorkflowFormRelation relation : relations) {
                 relation.setProcessId(processInstance.getId());
             }
 
             formRelationService.saveBatch(relations);
-
-            for (Session session : sessionList) {
-                session.getConnection().setAutoCommit(Boolean.FALSE);
-                session.commit();
-                session.close();
-            }
+            System.out.println("newLaunch start 8");
 
             return result;
         } catch (Exception e) {
-            for (Session session : sessionList) {
-                session.quietRollback();
-            }
             if (ObjectUtil.isNotEmpty(e.getMessage()) && e.getMessage().contains("sequence flow")) {
                 throw new MyException("流转条件错误,请检查流转条件设置!");
             } else {
@@ -1388,7 +1333,7 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
 
                 relations.add(formRelation);
             } catch (Exception e) {
-                log.error("提交表单数据失败(reLaunch):",e);
+                log.error("提交表单数据失败(reLaunch):", e);
                 for (Session session : sessionList) {
                     session.quietRollback();
                 }
@@ -1466,7 +1411,7 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
             } else {
                 throw new MyException("表单提交错误, 请联系系统管理员!");
             }
-        }finally {
+        } finally {
             for (Session session : sessionList) {
                 session.close();
             }
@@ -1592,8 +1537,8 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
         User user = tokenSession.get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
         List<String> taskIds = new ArrayList<>();
         List<WorkflowApproveRecord> list = approveRecordService.list(
-            new QueryWrapper<WorkflowApproveRecord>().lambda()
-            .eq(WorkflowApproveRecord::getApproveUserId, user.getId())
+                new QueryWrapper<WorkflowApproveRecord>().lambda()
+                        .eq(WorkflowApproveRecord::getApproveUserId, user.getId())
         );
         taskIds = list.stream().map(WorkflowApproveRecord::getTaskId).collect(Collectors.toList());
 //        if(dto.getStatus() != null && dto.getStatus() == 1){
@@ -1697,9 +1642,6 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
             variableMap.putValue(variableInstance.getName(), variableInstance.getValue());
         }
 
-        //定义sessionList  存储所有表提交的session  用于最后提交commit  保证事务
-        List<Session> sessionList = new ArrayList<>(userTaskConfig.getFormConfigs().size());
-
         //获取流程变量的值
         Object variable = runtimeService.getVariable(task.getProcessInstanceId(), WorkflowConstant.PROCESS_PARAM_KEY);
 
@@ -1773,8 +1715,7 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
                     executeWorkflowUpdateDto.setFormData(formData);
 
                     Triple<Session, Long, Long> sessionLongLongTriple = formExecuteService.workflowUpdate(executeWorkflowUpdateDto);
-                    //如果是已经提交过的表单 变量keyValueMap 已经存在 没有必要在新增
-                    sessionList.add(sessionLongLongTriple.getLeft());
+
 
                 } else {
                     //如果没有提交过 默认是add
@@ -1783,7 +1724,6 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
                     executeWorkflowAddDto.setFormData(formData);
 
                     Triple<Session, Long, Long> sessionLongLongTriple = formExecuteService.workflowAdd(executeWorkflowAddDto);
-                    sessionList.add(sessionLongLongTriple.getLeft());
 
                     WorkflowFormRelation relation = new WorkflowFormRelation();
                     relation.setProcessId(task.getProcessInstanceId());
@@ -2080,16 +2020,7 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
 
             updateFileInfo(dto.getFileFolderIds(), task.getProcessInstanceId());
 
-            for (Session session : sessionList) {
-                session.getConnection().setAutoCommit(Boolean.FALSE);
-                session.commit();
-                session.close();
-            }
-
         } catch (Exception e) {
-            for (Session session : sessionList) {
-                session.quietRollback();
-            }
             if (e.getMessage().contains("sequence flow")) {
                 throw new MyException("流转条件错误,请检查流转条件设置!");
             } else {
@@ -2435,7 +2366,7 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
             } else {
                 throw new MyException("表单提交错误, 请联系系统管理员!");
             }
-        }finally {
+        } finally {
             for (Session session : sessionList) {
                 session.close();
             }
@@ -2761,7 +2692,6 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
         }
 
         List<ProcessRecordListVo> recordListVos = getProcessRecordListVos(task.getProcessInstanceId(), 0);
-        // List<ProcessRecordListVo> recordListVos = getCustomProcessRecordListVos(task.getProcessInstanceId(), 0);
         vo.setTaskRecords(recordListVos);
 
         //将map 转为 java类
@@ -2827,7 +2757,6 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
             throw new MyException("当前任务没有开始节点");
         }
         List<ProcessRecordListVo> recordListVos = getProcessRecordListVos(task.getProcessInstanceId(), 0);
-        // List<ProcessRecordListVo> recordListVos = getCustomProcessRecordListVos(task.getProcessInstanceId(), 0);
         vo.setTaskRecords(recordListVos);
 
         //查询任务关联任务
@@ -2922,7 +2851,6 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
 
 
         List<ProcessRecordListVo> recordListVos = getProcessRecordListVos(processId, 0);
-        // List<ProcessRecordListVo> recordListVos = getCustomProcessRecordListVos(processId, 0);
         vo.setTaskRecords(recordListVos);
 
         List<Object> allFormConfigs = workflowSchemaConfig.getChildNodeConfig().stream().filter(x -> x.containsKey("formConfigs")).map(x -> x.get("formConfigs")).collect(Collectors.toList());
@@ -3001,7 +2929,6 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
             throw new MyException("当前任务没有开始节点");
         }
         List<ProcessRecordListVo> recordListVos = getProcessRecordListVos(historicTaskInstance.getProcessInstanceId(), 0);
-        // List<ProcessRecordListVo> recordListVos = getCustomProcessRecordListVos(historicTaskInstance.getProcessInstanceId(), 0);
         vo.setTaskRecords(recordListVos);
 
         //查询任务关联任务
@@ -3210,13 +3137,13 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
             List<String> currentTask = list.stream().map(Task::getTaskDefinitionKey).distinct().collect(Collectors.toList());
             vo.setCurrentNodes(currentTask);
         }
+
         return vo;
     }
 
     @Override
     public List<ProcessRecordListVo> getProcessRecord(String processInstanceId) {
         return getProcessRecordListVos(processInstanceId, 0);
-        // return getCustomProcessRecordListVos(processInstanceId, 0);
     }
 
     @Override
@@ -3657,7 +3584,6 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
         record.setNodeMultiType(WorkflowMultiInstanceType.NONE.getCode());
         record.setRecordTime(LocalDateTime.now());
         String oldTaskName = workflowExtra.getTaskName();
-
         //如果传入的是开始节点的值  默认是关闭流程  重新发起
         if (StrUtil.equals(dto.getActivityId(), historicProcessInstance.getStartActivityId())) {
 

+ 5314 - 0
src/main/java/com/xjrsoft/module/workflow/service/impl/WorkflowExecuteServiceImpl.java.back

@@ -0,0 +1,5314 @@
+package com.xjrsoft.module.workflow.service.impl;
+
+import cn.dev33.satoken.session.SaSession;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.db.Session;
+import cn.hutool.extra.spring.SpringUtil;
+import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.StringPool;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.github.yulichang.toolkit.MPJWrappers;
+import com.github.yulichang.wrapper.MPJLambdaWrapper;
+import com.xjrsoft.common.constant.GlobalConstant;
+import com.xjrsoft.common.enums.EnabledMark;
+import com.xjrsoft.common.enums.FormTemplateType;
+import com.xjrsoft.common.enums.WorkflowApproveType;
+import com.xjrsoft.common.enums.WorkflowAutoAgreeType;
+import com.xjrsoft.common.enums.WorkflowIsPrevChooseNextType;
+import com.xjrsoft.common.enums.WorkflowIsRecycleType;
+import com.xjrsoft.common.enums.WorkflowMultiInstanceFinishType;
+import com.xjrsoft.common.enums.WorkflowMultiInstanceType;
+import com.xjrsoft.common.enums.WorkflowNoHandlerType;
+import com.xjrsoft.common.enums.WorkflowRelationAuthType;
+import com.xjrsoft.common.enums.YesOrNoEnum;
+import com.xjrsoft.common.exception.MyException;
+import com.xjrsoft.common.page.ConventPage;
+import com.xjrsoft.common.page.PageOutput;
+import com.xjrsoft.common.utils.RedisUtil;
+import com.xjrsoft.common.utils.VoToColumnUtil;
+import com.xjrsoft.module.form.dto.FormExecuteWorkflowAddDto;
+import com.xjrsoft.module.form.dto.FormExecuteWorkflowUpdateDto;
+import com.xjrsoft.module.form.entity.FormTemplate;
+import com.xjrsoft.module.form.mapper.FormTemplateMapper;
+import com.xjrsoft.module.form.service.IFormExecuteService;
+import com.xjrsoft.module.magicapi.service.IMagicApiService;
+import com.xjrsoft.module.magicapi.vo.MagicApiInfoVo;
+import com.xjrsoft.module.organization.entity.User;
+import com.xjrsoft.module.organization.entity.UserRoleRelation;
+import com.xjrsoft.module.organization.service.IUserService;
+import com.xjrsoft.module.system.entity.File;
+import com.xjrsoft.module.system.entity.Stamp;
+import com.xjrsoft.module.system.service.IFileService;
+import com.xjrsoft.module.system.service.IStampService;
+import com.xjrsoft.module.workflow.constant.WorkflowConstant;
+import com.xjrsoft.module.workflow.dto.AddOrSubSignDto;
+import com.xjrsoft.module.workflow.dto.ApproveDto;
+import com.xjrsoft.module.workflow.dto.ApproveMultiDto;
+import com.xjrsoft.module.workflow.dto.ApproveMultiInfoDto;
+import com.xjrsoft.module.workflow.dto.ApproveUserDto;
+import com.xjrsoft.module.workflow.dto.ApproveUserMultiDto;
+import com.xjrsoft.module.workflow.dto.CirculatedTaskPageDto;
+import com.xjrsoft.module.workflow.dto.DeployDto;
+import com.xjrsoft.module.workflow.dto.DraftPageDto;
+import com.xjrsoft.module.workflow.dto.FinishedTaskPageDto;
+import com.xjrsoft.module.workflow.dto.FormFinishedTaskDto;
+import com.xjrsoft.module.workflow.dto.GetAssigneeDto;
+import com.xjrsoft.module.workflow.dto.LaunchDto;
+import com.xjrsoft.module.workflow.dto.LaunchRelationTaskDto;
+import com.xjrsoft.module.workflow.dto.MonitorPageDto;
+import com.xjrsoft.module.workflow.dto.MoveRecycleDto;
+import com.xjrsoft.module.workflow.dto.MyExaminePageDto;
+import com.xjrsoft.module.workflow.dto.MyProcessPageDto;
+import com.xjrsoft.module.workflow.dto.PendingTaskPageDto;
+import com.xjrsoft.module.workflow.dto.ReLaunchDto;
+import com.xjrsoft.module.workflow.dto.RecycleDeleteDto;
+import com.xjrsoft.module.workflow.dto.RecycleProcessPageDto;
+import com.xjrsoft.module.workflow.dto.RejectNodeDto;
+import com.xjrsoft.module.workflow.dto.RelationTaskInfoDto;
+import com.xjrsoft.module.workflow.dto.RelationTaskPageDto;
+import com.xjrsoft.module.workflow.dto.RestartDto;
+import com.xjrsoft.module.workflow.dto.SaveDraftDto;
+import com.xjrsoft.module.workflow.dto.SetAssigneeDto;
+import com.xjrsoft.module.workflow.dto.SetSuspendedDto;
+import com.xjrsoft.module.workflow.dto.TransferDto;
+import com.xjrsoft.module.workflow.dto.UpdateDraftDto;
+import com.xjrsoft.module.workflow.dto.WithdrawDto;
+import com.xjrsoft.module.workflow.entity.WorkflowApproveRecord;
+import com.xjrsoft.module.workflow.entity.WorkflowCirculated;
+import com.xjrsoft.module.workflow.entity.WorkflowDelegate;
+import com.xjrsoft.module.workflow.entity.WorkflowDraft;
+import com.xjrsoft.module.workflow.entity.WorkflowExtra;
+import com.xjrsoft.module.workflow.entity.WorkflowFormRelation;
+import com.xjrsoft.module.workflow.entity.WorkflowRecord;
+import com.xjrsoft.module.workflow.entity.WorkflowSchema;
+import com.xjrsoft.module.workflow.mapper.WorkflowDelegateMapper;
+import com.xjrsoft.module.workflow.mapper.WorkflowExtraMapper;
+import com.xjrsoft.module.workflow.mapper.WorkflowRecordMapper;
+import com.xjrsoft.module.workflow.mapper.WorkflowSchemaMapper;
+import com.xjrsoft.module.workflow.mapper.XjrWorkflowExtraMapper;
+import com.xjrsoft.module.workflow.model.ApiConfig;
+import com.xjrsoft.module.workflow.model.ApiRequestParamsConfig;
+import com.xjrsoft.module.workflow.model.AuthConfig;
+import com.xjrsoft.module.workflow.model.ButtonConfig;
+import com.xjrsoft.module.workflow.model.FormAssignmentConfig;
+import com.xjrsoft.module.workflow.model.FormConfig;
+import com.xjrsoft.module.workflow.model.MemberConfig;
+import com.xjrsoft.module.workflow.model.ProcessParamConfig;
+import com.xjrsoft.module.workflow.model.RelationProcessConfig;
+import com.xjrsoft.module.workflow.model.StartNodeConfig;
+import com.xjrsoft.module.workflow.model.UserTaskConfig;
+import com.xjrsoft.module.workflow.model.WorkflowSchemaConfig;
+import com.xjrsoft.module.workflow.service.IWorkflowApproveRecordService;
+import com.xjrsoft.module.workflow.service.IWorkflowCirculatedService;
+import com.xjrsoft.module.workflow.service.IWorkflowDraftService;
+import com.xjrsoft.module.workflow.service.IWorkflowExecuteService;
+import com.xjrsoft.module.workflow.service.IWorkflowExtraService;
+import com.xjrsoft.module.workflow.service.IWorkflowFormRelationService;
+import com.xjrsoft.module.workflow.service.IWorkflowRecordService;
+import com.xjrsoft.module.workflow.utils.WorkFlowUtil;
+import com.xjrsoft.module.workflow.vo.AllRecordListVo;
+import com.xjrsoft.module.workflow.vo.ApproveMultiInfoVo;
+import com.xjrsoft.module.workflow.vo.ApproveMultiVo;
+import com.xjrsoft.module.workflow.vo.CirculatedTaskPageVo;
+import com.xjrsoft.module.workflow.vo.DraftInfoVo;
+import com.xjrsoft.module.workflow.vo.DraftPageVo;
+import com.xjrsoft.module.workflow.vo.FinishedTaskPageVo;
+import com.xjrsoft.module.workflow.vo.FinishedTaskVo;
+import com.xjrsoft.module.workflow.vo.FormFinishedTaskVo;
+import com.xjrsoft.module.workflow.vo.GetAssigneeVo;
+import com.xjrsoft.module.workflow.vo.GetCountVo;
+import com.xjrsoft.module.workflow.vo.HistoryTaskVo;
+import com.xjrsoft.module.workflow.vo.LaunchAndApproveVo;
+import com.xjrsoft.module.workflow.vo.MonitorPageVo;
+import com.xjrsoft.module.workflow.vo.MyProcessPageVo;
+import com.xjrsoft.module.workflow.vo.PendingTaskVo;
+import com.xjrsoft.module.workflow.vo.ProcessInfoVo;
+import com.xjrsoft.module.workflow.vo.ProcessRecordListVo;
+import com.xjrsoft.module.workflow.vo.RecycleProcessInfoVo;
+import com.xjrsoft.module.workflow.vo.RecycleProcessPageVo;
+import com.xjrsoft.module.workflow.vo.RejectNodeVo;
+import com.xjrsoft.module.workflow.vo.RelationFormInfoVo;
+import com.xjrsoft.module.workflow.vo.RelationTaskInfoVo;
+import com.xjrsoft.module.workflow.vo.RelationTaskPageVo;
+import com.xjrsoft.module.workflow.vo.RestartVo;
+import com.xjrsoft.module.workflow.vo.StartNodeFormInfoVo;
+import com.xjrsoft.module.workflow.vo.StartProcessInfoVo;
+import com.xjrsoft.module.workflow.vo.StartProcessRelationTaskVo;
+import com.xjrsoft.module.workflow.vo.TaskInfoRelationTaskVo;
+import com.xjrsoft.module.workflow.vo.TaskInfoVo;
+import com.xjrsoft.module.workflow.vo.UserTaskFormInfoVo;
+import com.xjrsoft.module.workflow.vo.UserTaskInfoVo;
+import com.xjrsoft.module.workflow.vo.UserTaskRelationTaskVo;
+import com.xjrsoft.module.workflow.vo.WorkflowSchemaInfoVo;
+import lombok.AllArgsConstructor;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.tuple.ImmutableTriple;
+import org.apache.commons.lang3.tuple.Triple;
+import org.camunda.bpm.engine.HistoryService;
+import org.camunda.bpm.engine.RepositoryService;
+import org.camunda.bpm.engine.RuntimeService;
+import org.camunda.bpm.engine.TaskService;
+import org.camunda.bpm.engine.history.HistoricActivityInstance;
+import org.camunda.bpm.engine.history.HistoricProcessInstance;
+import org.camunda.bpm.engine.history.HistoricProcessInstanceQuery;
+import org.camunda.bpm.engine.history.HistoricTaskInstance;
+import org.camunda.bpm.engine.history.HistoricTaskInstanceQuery;
+import org.camunda.bpm.engine.history.HistoricVariableInstance;
+import org.camunda.bpm.engine.impl.persistence.entity.HistoricVariableInstanceEntity;
+import org.camunda.bpm.engine.impl.persistence.entity.TaskEntity;
+import org.camunda.bpm.engine.repository.Deployment;
+import org.camunda.bpm.engine.repository.ProcessDefinition;
+import org.camunda.bpm.engine.runtime.ActivityInstance;
+import org.camunda.bpm.engine.runtime.ProcessInstance;
+import org.camunda.bpm.engine.runtime.VariableInstance;
+import org.camunda.bpm.engine.task.Task;
+import org.camunda.bpm.engine.task.TaskQuery;
+import org.camunda.bpm.engine.variable.VariableMap;
+import org.camunda.bpm.engine.variable.Variables;
+import org.camunda.bpm.model.bpmn.BpmnModelInstance;
+import org.camunda.bpm.model.bpmn.impl.instance.FlowNodeImpl;
+import org.camunda.bpm.model.bpmn.instance.SequenceFlow;
+import org.camunda.bpm.model.xml.instance.ModelElementInstance;
+import org.camunda.commons.utils.IoUtil;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.ssssssss.magicapi.core.service.MagicAPIService;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * @Author: tzx
+ * @Date: 2022/9/8 14:25
+ */
+@Slf4j
+@Service
+@AllArgsConstructor
+public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
+
+    private final WorkflowSchemaMapper workflowSchemaMapper;
+
+    private final RuntimeService runtimeService;
+
+    private final RepositoryService repositoryService;
+
+    private final TaskService taskService;
+
+    private final IFormExecuteService formExecuteService;
+
+    private final RedisUtil redisUtil;
+
+    private final WorkflowExtraMapper workflowExtraMapper;
+
+    private final HistoryService historyService;
+
+    private final FormTemplateMapper formTemplateMapper;
+
+    private final IWorkflowDraftService workflowDraftService;
+
+    private final WorkflowDelegateMapper workflowDelegateMapper;
+
+    private final WorkflowRecordMapper workflowRecordMapper;
+
+    private final IWorkflowCirculatedService circulatedService;
+
+    private final IWorkflowApproveRecordService approveRecordService;
+
+    private final IStampService stampService;
+
+    private final IWorkflowExtraService extraService;
+
+
+    private final IFileService fileService;
+
+    private final IWorkflowFormRelationService formRelationService;
+
+    private final IUserService userService;
+
+    private final ObjectMapper objectMapper;
+
+    private final XjrWorkflowExtraMapper xjrWorkflowExtraMapper;
+    /**
+     * 数据库存储xml字段的后缀
+     */
+    private static final String DB_FIELD_XML_PREFIX = "xml";
+
+
+    @Override
+    public boolean deploy(DeployDto dto) {
+        WorkflowSchema workflowSchema = workflowSchemaMapper.selectById(dto.getSchemaId());
+
+        Deployment deploy = repositoryService.createDeployment().name(workflowSchema.getName()).addInputStream(workflowSchema.getName() + StringPool.DOT + WorkflowConstant.WORKFLOW_SUFFIX, IoUtil.stringAsInputStream(workflowSchema.getXmlContent())).deploy();
+        workflowSchema.setDeploymentId(deploy.getId());
+
+        return workflowSchemaMapper.updateById(workflowSchema) > 0;
+    }
+
+    @Override
+    public String preview(Long schemaId) {
+
+        //排除xml 查出数据
+        WorkflowSchema workflowSchema = workflowSchemaMapper.selectOne(Wrappers.lambdaQuery(WorkflowSchema.class).eq(WorkflowSchema::getId, schemaId).select(x -> x.getProperty().startsWith(DB_FIELD_XML_PREFIX)));
+
+        return workflowSchema.getXmlContent();
+    }
+
+    @Override
+    public StartProcessInfoVo getStartProcessInfo(Long schemaId) {
+
+        //排除xml 查出数据
+        WorkflowSchema workflowSchema = workflowSchemaMapper.selectOne(Wrappers.lambdaQuery(WorkflowSchema.class).eq(WorkflowSchema::getId, schemaId));
+
+        StartProcessInfoVo vo = new StartProcessInfoVo();
+
+        vo.setWorkflowChat(workflowSchema.getWorkflowChat());
+
+        //获取到整个流程模板的配置
+        WorkflowSchemaConfig workflowSchemaConfig = JSONUtil.toBean(workflowSchema.getJsonContent(), WorkflowSchemaConfig.class);
+        //流程参数  发布时  存到变量中
+
+        List<RelationProcessConfig> relationProcessConfig = workflowSchemaConfig.getProcessConfig().getRelationProcessConfigs();
+
+        List<Long> relationSchemaIds = relationProcessConfig.stream().map(RelationProcessConfig::getId).collect(Collectors.toList());
+
+        if (relationSchemaIds.size() > 0) {
+            LambdaQueryWrapper<WorkflowSchema> queryWrapper = new LambdaQueryWrapper<>();
+            queryWrapper.in(WorkflowSchema::getId, relationSchemaIds);
+            queryWrapper.select(WorkflowSchema::getId, WorkflowSchema::getName);
+            List<WorkflowSchema> workflowSchemas = workflowSchemaMapper.selectList(queryWrapper);
+
+            List<StartProcessRelationTaskVo> relationTasks = new ArrayList<>(workflowSchemas.size());
+            for (WorkflowSchema schema : workflowSchemas) {
+                StartProcessRelationTaskVo relationTaskVo = new StartProcessRelationTaskVo();
+                relationTaskVo.setSchemaId(schema.getId());
+                relationTaskVo.setSchemaName(schema.getName());
+                relationTasks.add(relationTaskVo);
+            }
+            vo.setRelationTasks(relationTasks);
+        }
+
+
+        Optional<Map<String, Object>> startNodeConfigMap = workflowSchemaConfig.getChildNodeConfig().stream().filter(c -> c.containsValue(WorkflowConstant.START_NODE_DEFAULT_ID)).findFirst();
+
+        if (!startNodeConfigMap.isPresent()) {
+            throw new MyException("找不到当前流程的开始节点配置!");
+        }
+
+        //将map 转为 java类
+        StartNodeConfig startNodeConfig = Convert.convert(StartNodeConfig.class, startNodeConfigMap.get());
+
+        List<Long> formIds = startNodeConfig.getFormConfigs().stream().map(FormConfig::getFormId).collect(Collectors.toList());
+        List<FormTemplate> formTemplates = formTemplateMapper.selectList(Wrappers.lambdaQuery(FormTemplate.class).in(formIds.size() > 0, FormTemplate::getId, formIds));
+
+        List<StartNodeFormInfoVo> formInfoVos = new ArrayList<>(startNodeConfig.getFormConfigs().size());
+
+
+        for (FormConfig formConfig : startNodeConfig.getFormConfigs()) {
+
+            StartNodeFormInfoVo formInfoVo = new StartNodeFormInfoVo();
+            formInfoVo.setFormType(formConfig.getFormType());
+            formInfoVo.setFormConfig(formConfig);
+
+            //TODO 系统表单 和 自定义表单 走同一套流程  都是使用json  以后看能否有更好的解决方案 解决用户手动修改系统表单代码
+            if (formConfig.getFormType() == FormTemplateType.CUSTOM.getCode() || formConfig.getFormType() == FormTemplateType.SYSTEM.getCode()) {
+                Optional<FormTemplate> templateOp = formTemplates.stream().filter(f -> Objects.equals(f.getId(), formConfig.getFormId())).findFirst();
+                templateOp.ifPresent(t -> formInfoVo.setFormJson(t.getFormJson()));
+            }
+
+            formInfoVos.add(formInfoVo);
+        }
+        vo.setFormInfos(formInfoVos);
+        vo.setSchemaInfo(BeanUtil.toBean(workflowSchema, WorkflowSchemaInfoVo.class));
+
+        //获取流程数据
+        List<FormAssignmentConfig> formAssignmentConfigs = startNodeConfig.getAssignmentConfig().getFormAssignmentConfigs();
+
+        //是否有表单赋值
+        if (formAssignmentConfigs.size() > 0) {
+
+            List<ProcessParamConfig> processParamConfigs = workflowSchemaConfig.getProcessConfig().getProcessParamConfigs();
+
+            long count = historyService.createHistoricProcessInstanceQuery().count();
+            Map<String, Object> processParam = WorkFlowUtil.getProcessParam(processParamConfigs, workflowSchema, count + 1, null);
+
+            Map<String, Map<String, Object>> formAssignmentData = new HashMap<>();
+
+            for (FormAssignmentConfig formAssignmentConfig : formAssignmentConfigs) {
+
+                if (formAssignmentData.containsKey(formAssignmentConfig.getTarget().getFormId())) {
+                    Map<String, Object> thisFormAssignmentData = formAssignmentData.get(formAssignmentConfig.getTarget().getFormId());
+                    thisFormAssignmentData.put(formAssignmentConfig.getTarget().getFormField(), processParam.get(formAssignmentConfig.getSource()));
+                } else {
+                    Map<String, Object> thisFormAssignmentData = new HashMap<>();
+                    thisFormAssignmentData.put(formAssignmentConfig.getTarget().getFormField(), processParam.get(formAssignmentConfig.getSource()));
+                    formAssignmentData.put(formAssignmentConfig.getTarget().getFormId(), thisFormAssignmentData);
+                }
+
+            }
+
+            vo.setFormAssignmentData(formAssignmentData);
+
+        }
+
+
+        return vo;
+    }
+
+
+    @Override
+    public UserTaskInfoVo getApproveProcessInfo(String taskId) {
+
+        HistoricTaskInstance task = historyService.createHistoricTaskInstanceQuery().taskId(taskId).singleResult();
+        if (task == null) {
+            throw new MyException("找不到该流程!");
+        }
+        List<HistoricVariableInstance> variableInstanceList = historyService.createHistoricVariableInstanceQuery()
+                .processInstanceId(task.getProcessInstanceId())
+                .variableNameIn(WorkflowConstant.PROCESS_SCHEMA_ID_KEY, WorkflowConstant.RELATION_TASK_KEY)
+                .list();
+
+        Optional<HistoricVariableInstance> schemaIdVar = variableInstanceList.stream().filter(x -> x.getName().equals(WorkflowConstant.PROCESS_SCHEMA_ID_KEY)).findFirst();
+
+        if (!schemaIdVar.isPresent()) {
+            throw new MyException("找不到此模板!");
+        }
+
+        //排除xml 查出数据
+        WorkflowSchema workflowSchema = workflowSchemaMapper.selectOne(Wrappers.lambdaQuery(WorkflowSchema.class).eq(WorkflowSchema::getId, schemaIdVar.get().getValue()));
+
+        UserTaskInfoVo vo = new UserTaskInfoVo();
+        vo.setWorkflowChat(workflowSchema.getWorkflowChat());
+
+        //获取到整个流程模板的配置
+        WorkflowSchemaConfig workflowSchemaConfig = JSONUtil.toBean(workflowSchema.getJsonContent(), WorkflowSchemaConfig.class);
+
+        Optional<HistoricVariableInstance> relationTasksOp = variableInstanceList.stream().filter(x -> x.getName().equals(WorkflowConstant.RELATION_TASK_KEY)).findFirst();
+
+        //如果关联任务不为空
+        if (relationTasksOp.isPresent()) {
+            List<LaunchRelationTaskDto> relationTasks = Convert.toList(LaunchRelationTaskDto.class, relationTasksOp.get().getValue());
+
+            if (relationTasks != null && relationTasks.size() > 0) {
+
+                List<Long> relationSchemaIds = relationTasks.stream().map(LaunchRelationTaskDto::getSchemaId).collect(Collectors.toList());
+
+                LambdaQueryWrapper<WorkflowSchema> queryWrapper = new LambdaQueryWrapper<>();
+                queryWrapper.in(WorkflowSchema::getId, relationSchemaIds);
+                queryWrapper.select(WorkflowSchema::getId, WorkflowSchema::getName);
+                List<WorkflowSchema> workflowSchemas = workflowSchemaMapper.selectList(queryWrapper);
+                List<UserTaskRelationTaskVo> relationTasksVo = new ArrayList<>(workflowSchemas.size());
+
+                for (LaunchRelationTaskDto relationTask : relationTasks) {
+                    UserTaskRelationTaskVo relationTaskVo = new UserTaskRelationTaskVo();
+                    relationTaskVo.setTaskId(relationTask.getTaskId());
+                    relationTaskVo.setSchemaId(relationTask.getSchemaId());
+                    Optional<WorkflowSchema> thisSchema = workflowSchemas.stream().filter(schema -> schema.getId().equals(relationTask.getSchemaId())).findFirst();
+                    thisSchema.ifPresent(schema -> {
+                        relationTaskVo.setSchemaName(schema.getName());
+                    });
+                    relationTasksVo.add(relationTaskVo);
+                }
+                vo.setRelationTasks(relationTasksVo);
+            }
+
+        }
+
+        Optional<Map<String, Object>> taskNodeConfigMap = workflowSchemaConfig.getChildNodeConfig().stream().filter(c -> c.containsValue(task.getTaskDefinitionKey())).findFirst();
+
+        if (!taskNodeConfigMap.isPresent()) {
+            throw new MyException("找不到当前节点的配置信息!");
+        }
+
+        UserTaskConfig userTaskConfig = Convert.convert(UserTaskConfig.class, taskNodeConfigMap.get());
+
+        List<Long> formIds = userTaskConfig.getFormConfigs().stream().map(FormConfig::getFormId).collect(Collectors.toList());
+        String[] formKeys = userTaskConfig.getFormConfigs().stream().map(FormConfig::getKey).toArray(String[]::new);
+        List<FormTemplate> formTemplates = formTemplateMapper.selectList(Wrappers.lambdaQuery(FormTemplate.class).in(formIds.size() > 0, FormTemplate::getId, formIds));
+
+        List<HistoricVariableInstance> allFormData = historyService.createHistoricVariableInstanceQuery()
+                .processInstanceId(task.getProcessInstanceId())
+                .variableNameIn(formKeys)
+                .list();
+
+
+        List<UserTaskFormInfoVo> formInfoVos = new ArrayList<>(userTaskConfig.getFormConfigs().size());
+        for (FormConfig formConfig : userTaskConfig.getFormConfigs()) {
+
+            UserTaskFormInfoVo formInfoVo = new UserTaskFormInfoVo();
+            formInfoVo.setFormType(formConfig.getFormType());
+            formInfoVo.setFormConfig(formConfig);
+
+            if (allFormData.stream().anyMatch(x -> x.getName().equals(formConfig.getKey()))) {
+                HistoricVariableInstance historicVariableInstance = allFormData.stream().filter(x -> x.getName().equals(formConfig.getKey())).findFirst().orElse(new HistoricVariableInstanceEntity());
+                formInfoVo.setFormData(Convert.toMap(String.class, Object.class, historicVariableInstance.getValue()));
+            }
+
+            //TODO 系统表单 和 自定义表单 走同一套流程  都是使用json  以后看能否有更好的解决方案 解决用户手动修改系统表单代码
+            if (formConfig.getFormType() == FormTemplateType.CUSTOM.getCode() || formConfig.getFormType() == FormTemplateType.SYSTEM.getCode()) {
+                Optional<FormTemplate> templateOp = formTemplates.stream().filter(f -> Objects.equals(f.getId(), formConfig.getFormId())).findFirst();
+                templateOp.ifPresent(t -> formInfoVo.setFormJson(t.getFormJson()));
+            }
+
+            formInfoVos.add(formInfoVo);
+        }
+        vo.setFormInfos(formInfoVos);
+        vo.setSchemaInfo(BeanUtil.toBean(workflowSchema, WorkflowSchemaInfoVo.class));
+        vo.setOpinionConfig(userTaskConfig.getOpinionConfig());
+
+        //如果是多实例的
+        if (userTaskConfig.getCountersignConfig().getMultipleInstancesType() != WorkflowMultiInstanceType.NONE.getCode()) {
+            vo.setIsAddOrSubSign(userTaskConfig.getCountersignConfig().getAddOrRemove());
+            //如果不是none  就代表是会签节点
+            vo.setIsCountersign(Boolean.TRUE);
+            vo.setButtonConfigs(userTaskConfig.getButtonConfigs().stream().filter(ButtonConfig::getChecked).filter(buttonConfig -> buttonConfig.getApproveType() == WorkflowApproveType.AGREE.getCode() || buttonConfig.getApproveType() == WorkflowApproveType.DISAGREE.getCode()).collect(Collectors.toList()));
+
+        } else {
+            vo.setIsCountersign(Boolean.FALSE);
+            vo.setButtonConfigs(userTaskConfig.getButtonConfigs().stream().filter(ButtonConfig::getChecked).collect(Collectors.toList()));
+
+        }
+
+        if (userTaskConfig.getOpinionConfig().getEnabled()) {
+            MPJLambdaWrapper<WorkflowApproveRecord> workflowApproveRecordMPJLambdaWrapper = MPJWrappers.<WorkflowApproveRecord>lambdaJoin()
+                    .disableSubLogicDel()
+                    .eq(WorkflowApproveRecord::getProcessId, task.getProcessInstanceId())
+                    .select(WorkflowApproveRecord::getId)
+                    .select(WorkflowApproveRecord.class, x -> VoToColumnUtil.fieldsToColumns(WorkflowApproveRecord.class).contains(x.getProperty()))
+                    .selectAs(User::getName, WorkflowApproveRecord::getApproveUserName)
+                    .leftJoin(User.class, User::getId, WorkflowApproveRecord::getApproveUserId)
+                    .selectAs(Stamp::getFileUrl, WorkflowApproveRecord::getApproveStampUrl)
+                    .leftJoin(Stamp.class, Stamp::getId, WorkflowApproveRecord::getApproveStamp);
+
+            List<WorkflowApproveRecord> approveRecords = approveRecordService.selectJoinList(WorkflowApproveRecord.class, workflowApproveRecordMPJLambdaWrapper);
+
+            //取时间最大值 不好取  目前还是全部查出来 然后根据时间 倒序 取第一条数据
+            if (userTaskConfig.getOpinionConfig().getShowType() == 1 && approveRecords.size() > 0) {
+                WorkflowApproveRecord approveRecord = approveRecords.stream().sorted(Comparator.comparing(WorkflowApproveRecord::getApproveTime).reversed()).collect(Collectors.toList()).get(0);
+                List<WorkflowApproveRecord> onlyOne = new ArrayList<>();
+                onlyOne.add(approveRecord);
+                vo.setTaskApproveOpinions(onlyOne);
+            } else {
+                vo.setTaskApproveOpinions(approveRecords);
+            }
+        }
+
+        //获取流程数据
+        List<FormAssignmentConfig> formAssignmentConfigs = userTaskConfig.getAssignmentConfig().getFormAssignmentConfigs();
+
+        long taskSize = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).count();
+        //是否有表单赋值
+        if (formAssignmentConfigs.size() > 0 && taskSize > 0) {//有任务才给表单进行赋值,防止结束之后点击查看时获取不到对应的流程参数。
+
+            Object variable = taskService.getVariable(taskId, WorkflowConstant.PROCESS_PARAM_KEY);
+            Map<String, Object> processParam = Convert.toMap(String.class, Object.class, variable);
+
+            Map<String, Map<String, Object>> formAssignmentData = new HashMap<>();
+
+            for (FormAssignmentConfig formAssignmentConfig : formAssignmentConfigs) {
+
+                if (formAssignmentData.containsKey(formAssignmentConfig.getTarget().getFormId())) {
+                    Map<String, Object> thisFormAssignmentData = formAssignmentData.get(formAssignmentConfig.getTarget().getFormId());
+                    thisFormAssignmentData.put(formAssignmentConfig.getTarget().getFormField(), processParam.get(formAssignmentConfig.getSource()));
+                } else {
+                    Map<String, Object> thisFormAssignmentData = new HashMap<>();
+                    thisFormAssignmentData.put(formAssignmentConfig.getTarget().getFormField(), processParam.get(formAssignmentConfig.getSource()));
+                    formAssignmentData.put(formAssignmentConfig.getTarget().getFormId(), thisFormAssignmentData);
+                }
+
+            }
+
+            vo.setFormAssignmentData(formAssignmentData);
+
+        }
+
+        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
+
+        String superProcessInstanceId = historicProcessInstance.getSuperProcessInstanceId();
+
+        List<Map<String, Object>> otherProcessApproveRecord = new ArrayList<>();
+
+        //此流程 是否有主流程  如果有 代表他是某个流程的子流程
+        if (StrUtil.isNotBlank(superProcessInstanceId)) {
+
+            HistoricVariableInstance historicVariableInstance = historyService.createHistoricVariableInstanceQuery().processInstanceId(superProcessInstanceId).variableName(WorkflowConstant.PROCESS_SCHEMA_NAME_KEY).singleResult();
+            //获取主流程审批记录
+            List<ProcessRecordListVo> processRecordListVos = getProcessRecordListVos(superProcessInstanceId, 0);
+
+            Map<String, Object> superProcessMap = new HashMap<>();
+            superProcessMap.put("schemaName", historicVariableInstance.getValue() + "(上级流程)");
+            superProcessMap.put("records", processRecordListVos);
+
+            otherProcessApproveRecord.add(superProcessMap);
+
+        }
+
+        //查看当前流程 是否包含子流程
+        List<HistoricProcessInstance> childProcess = historyService.createHistoricProcessInstanceQuery().superProcessInstanceId(task.getProcessInstanceId()).list();
+
+        if (childProcess.size() > 0) {
+            String[] strings = childProcess.stream().map(HistoricProcessInstance::getId).toArray(String[]::new);
+
+            List<HistoricVariableInstance> childSchemaNameVarList = historyService.createHistoricVariableInstanceQuery().processInstanceIdIn(strings).variableName(WorkflowConstant.PROCESS_SCHEMA_NAME_KEY).list();
+
+            for (HistoricProcessInstance process : childProcess) {
+                Optional<HistoricVariableInstance> varOp = childSchemaNameVarList.stream().filter(x -> x.getProcessInstanceId().equals(process.getId())).findFirst();
+
+                varOp.ifPresent(schemaNameVar -> {
+                    Map<String, Object> superProcessMap = new HashMap<>();
+                    superProcessMap.put("schemaName", schemaNameVar.getValue() + "(下级流程)");
+
+                    //获取主流程审批记录
+                    List<ProcessRecordListVo> processRecordListVos = getProcessRecordListVos(schemaNameVar.getProcessInstanceId(), 0);
+                    superProcessMap.put("records", processRecordListVos);
+
+                    otherProcessApproveRecord.add(superProcessMap);
+                });
+            }
+        }
+        //TODO  新增返回值  返回 主/子 流程 审批记录
+
+        List<ProcessRecordListVo> recordListVos = getProcessRecordListVos(task.getProcessInstanceId(), 0);
+        vo.setTaskRecords(recordListVos);
+        vo.setOtherProcessApproveRecord(otherProcessApproveRecord);
+        return vo;
+
+    }
+
+
+    @Override
+    public UserTaskInfoVo getApproveProcessInfoByProcessId(String processId) {
+
+        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processId).singleResult();
+
+        List<HistoricVariableInstance> variableInstanceList = historyService.createHistoricVariableInstanceQuery()
+                .processInstanceId(processId)
+                .variableNameIn(WorkflowConstant.PROCESS_SCHEMA_ID_KEY, WorkflowConstant.RELATION_TASK_KEY)
+                .list();
+
+        Optional<HistoricVariableInstance> schemaIdVar = variableInstanceList.stream().filter(x -> x.getName().equals(WorkflowConstant.PROCESS_SCHEMA_ID_KEY)).findFirst();
+
+
+        if (!schemaIdVar.isPresent()) {
+            throw new MyException("找不到此模板!");
+        }
+
+        //查询当前流程是否包含父亲流程
+        String superProcessInstanceId = historicProcessInstance.getSuperProcessInstanceId();
+
+        //查看当前流程 是否包含子流程
+        List<HistoricProcessInstance> childProcess = historyService.createHistoricProcessInstanceQuery().superProcessInstanceId(processId).list();
+
+        //排除xml 查出数据
+        WorkflowSchema workflowSchema = workflowSchemaMapper.selectOne(Wrappers.lambdaQuery(WorkflowSchema.class).eq(WorkflowSchema::getId, schemaIdVar.get().getValue()));
+
+        //获取到整个流程模板的配置
+        WorkflowSchemaConfig workflowSchemaConfig = JSONUtil.toBean(workflowSchema.getJsonContent(), WorkflowSchemaConfig.class);
+
+        UserTaskInfoVo vo = new UserTaskInfoVo();
+        vo.setWorkflowChat(workflowSchema.getWorkflowChat());
+        //如果 所有 节点 包含 用户任务 || 外部流程 ||子流程
+        if (workflowSchemaConfig.getChildNodeConfig().stream().anyMatch(x -> x.containsValue(WorkflowConstant.BPMN_XML_USER_TASK_TYPE_NAME) || x.containsValue(WorkflowConstant.BPMN_XML_CALL_ACTIVITY_TYPE_NAME) || x.containsValue(WorkflowConstant.BPMN_XML_SUB_PROCESS_TYPE_NAME))) {
+//            ActivityInstance activityInstance = runtimeService.getActivityInstance(processId);
+//
+//
+//            //如果没有使用processId 查询 基本可以代表 当前节点 不是用户任务节点  是外部任务 子任务节点
+//            ActivityInstance childActivityInstance = activityInstance.getChildActivityInstances()[0];
+
+
+            List<WorkflowExtra> workflowExtras = workflowExtraMapper.selectList(Wrappers.lambdaQuery(WorkflowExtra.class).in(WorkflowExtra::getProcessId, processId));
+
+            //找到当前流程的 最新的一个用户任务数据
+            Optional<WorkflowExtra> lastUserTaskOp = workflowExtras.stream()
+                    .filter(e -> e.getProcessId().equals(processId) && StrUtil.isNotBlank(e.getTaskId()))
+                    .max(Comparator.comparing(WorkflowExtra::getStartTime));
+
+            //如果不为空 能找到  就使用这个用户任务 查看流程
+            if (lastUserTaskOp.isPresent()) {
+
+                WorkflowExtra workflowExtra = lastUserTaskOp.get();
+
+                Optional<HistoricVariableInstance> relationTasksOp = variableInstanceList.stream().filter(x -> x.getName().equals(WorkflowConstant.RELATION_TASK_KEY)).findFirst();
+
+                //如果关联任务不为空
+                if (relationTasksOp.isPresent()) {
+                    List<LaunchRelationTaskDto> relationTasks = Convert.toList(LaunchRelationTaskDto.class, relationTasksOp.get().getValue());
+
+                    if (relationTasks != null && relationTasks.size() > 0) {
+
+                        List<Long> relationSchemaIds = relationTasks.stream().map(LaunchRelationTaskDto::getSchemaId).collect(Collectors.toList());
+
+                        LambdaQueryWrapper<WorkflowSchema> queryWrapper = new LambdaQueryWrapper<>();
+                        queryWrapper.in(WorkflowSchema::getId, relationSchemaIds);
+                        queryWrapper.select(WorkflowSchema::getId, WorkflowSchema::getName);
+                        List<WorkflowSchema> workflowSchemas = workflowSchemaMapper.selectList(queryWrapper);
+                        List<UserTaskRelationTaskVo> relationTasksVo = new ArrayList<>(workflowSchemas.size());
+
+                        for (LaunchRelationTaskDto relationTask : relationTasks) {
+                            UserTaskRelationTaskVo relationTaskVo = new UserTaskRelationTaskVo();
+                            relationTaskVo.setTaskId(relationTask.getTaskId());
+                            relationTaskVo.setSchemaId(relationTask.getSchemaId());
+                            Optional<WorkflowSchema> thisSchema = workflowSchemas.stream().filter(schema -> schema.getId().equals(relationTask.getSchemaId())).findFirst();
+                            thisSchema.ifPresent(schema -> {
+                                relationTaskVo.setSchemaName(schema.getName());
+                            });
+                            relationTasksVo.add(relationTaskVo);
+                        }
+                        vo.setRelationTasks(relationTasksVo);
+                    }
+
+                }
+
+                //如果有taskId,表明不是纯粹的脚本任务,走以下逻辑
+                HistoricTaskInstance task = historyService.createHistoricTaskInstanceQuery().taskId(workflowExtra.getTaskId()).singleResult();
+
+                Optional<Map<String, Object>> taskNodeConfigMap = workflowSchemaConfig.getChildNodeConfig().stream().filter(c -> c.containsValue(task.getTaskDefinitionKey())).findFirst();
+
+                if (!taskNodeConfigMap.isPresent()) {
+                    throw new MyException("找不到当前节点的配置信息!");
+                }
+
+                UserTaskConfig userTaskConfig = Convert.convert(UserTaskConfig.class, taskNodeConfigMap.get());
+
+                List<Long> formIds = userTaskConfig.getFormConfigs().stream().map(FormConfig::getFormId).collect(Collectors.toList());
+                String[] formKeys = userTaskConfig.getFormConfigs().stream().map(FormConfig::getKey).toArray(String[]::new);
+                List<FormTemplate> formTemplates = formTemplateMapper.selectList(Wrappers.lambdaQuery(FormTemplate.class).in(formIds.size() > 0, FormTemplate::getId, formIds));
+
+                List<HistoricVariableInstance> allFormData = historyService.createHistoricVariableInstanceQuery()
+                        .processInstanceId(processId)
+                        .variableNameIn(formKeys)
+                        .list();
+
+
+                List<UserTaskFormInfoVo> formInfoVos = new ArrayList<>(userTaskConfig.getFormConfigs().size());
+                for (FormConfig formConfig : userTaskConfig.getFormConfigs()) {
+
+                    UserTaskFormInfoVo formInfoVo = new UserTaskFormInfoVo();
+                    formInfoVo.setFormType(formConfig.getFormType());
+                    formInfoVo.setFormConfig(formConfig);
+
+                    if (allFormData.stream().anyMatch(x -> x.getName().equals(formConfig.getKey()))) {
+                        HistoricVariableInstance historicVariableInstance = allFormData.stream().filter(x -> x.getName().equals(formConfig.getKey())).findFirst().orElse(new HistoricVariableInstanceEntity());
+                        formInfoVo.setFormData(Convert.toMap(String.class, Object.class, historicVariableInstance.getValue()));
+                    }
+
+                    //TODO 系统表单 和 自定义表单 走同一套流程  都是使用json  以后看能否有更好的解决方案 解决用户手动修改系统表单代码
+                    if (formConfig.getFormType() == FormTemplateType.CUSTOM.getCode() || formConfig.getFormType() == FormTemplateType.SYSTEM.getCode()) {
+                        Optional<FormTemplate> templateOp = formTemplates.stream().filter(f -> Objects.equals(f.getId(), formConfig.getFormId())).findFirst();
+                        templateOp.ifPresent(t -> formInfoVo.setFormJson(t.getFormJson()));
+                    }
+
+                    formInfoVos.add(formInfoVo);
+                }
+                vo.setFormInfos(formInfoVos);
+                vo.setSchemaInfo(BeanUtil.toBean(workflowSchema, WorkflowSchemaInfoVo.class));
+                vo.setButtonConfigs(userTaskConfig.getButtonConfigs().stream().filter(ButtonConfig::getChecked).collect(Collectors.toList()));
+                vo.setOpinionConfig(userTaskConfig.getOpinionConfig());
+
+                //如果是多实例的
+                if (userTaskConfig.getCountersignConfig().getMultipleInstancesType() != WorkflowMultiInstanceType.NONE.getCode()) {
+                    vo.setIsAddOrSubSign(userTaskConfig.getCountersignConfig().getAddOrRemove());
+                }
+
+                if (userTaskConfig.getOpinionConfig().getEnabled()) {
+                    MPJLambdaWrapper<WorkflowApproveRecord> workflowApproveRecordMPJLambdaWrapper = MPJWrappers.<WorkflowApproveRecord>lambdaJoin()
+                            .disableSubLogicDel()
+                            .eq(WorkflowApproveRecord::getProcessId, processId)
+                            .select(WorkflowApproveRecord::getId)
+                            .select(WorkflowApproveRecord.class, x -> VoToColumnUtil.fieldsToColumns(WorkflowApproveRecord.class).contains(x.getProperty()))
+                            .selectAs(User::getName, WorkflowApproveRecord::getApproveUserName)
+                            .leftJoin(User.class, User::getId, WorkflowApproveRecord::getApproveUserId)
+                            .selectAs(Stamp::getFileUrl, WorkflowApproveRecord::getApproveStampUrl)
+                            .leftJoin(Stamp.class, Stamp::getId, WorkflowApproveRecord::getApproveStamp);
+
+                    List<WorkflowApproveRecord> approveRecords = approveRecordService.selectJoinList(WorkflowApproveRecord.class, workflowApproveRecordMPJLambdaWrapper);
+
+                    //取时间最大值 不好取  目前还是全部查出来 然后根据时间 倒序 取第一条数据
+                    if (userTaskConfig.getOpinionConfig().getShowType() == 1 && approveRecords.size() > 0) {
+                        WorkflowApproveRecord approveRecord = approveRecords.stream().sorted(Comparator.comparing(WorkflowApproveRecord::getApproveTime).reversed()).collect(Collectors.toList()).get(0);
+                        List<WorkflowApproveRecord> onlyOne = new ArrayList<>();
+                        onlyOne.add(approveRecord);
+                        vo.setTaskApproveOpinions(onlyOne);
+                    } else {
+                        vo.setTaskApproveOpinions(approveRecords);
+                    }
+                }
+
+                //获取流程数据
+                List<FormAssignmentConfig> formAssignmentConfigs = userTaskConfig.getAssignmentConfig().getFormAssignmentConfigs();
+
+                long taskSize = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).count();
+
+                //是否有表单赋值
+                if (formAssignmentConfigs.size() > 0 && taskSize > 0) {
+
+                    Object variable = taskService.getVariable(workflowExtra.getTaskId(), WorkflowConstant.PROCESS_PARAM_KEY);
+                    Map<String, Object> processParam = Convert.toMap(String.class, Object.class, variable);
+
+                    Map<String, Map<String, Object>> formAssignmentData = new HashMap<>();
+
+                    for (FormAssignmentConfig formAssignmentConfig : formAssignmentConfigs) {
+
+                        if (formAssignmentData.containsKey(formAssignmentConfig.getTarget().getFormId())) {
+                            Map<String, Object> thisFormAssignmentData = formAssignmentData.get(formAssignmentConfig.getTarget().getFormId());
+                            thisFormAssignmentData.put(formAssignmentConfig.getTarget().getFormField(), processParam.get(formAssignmentConfig.getSource()));
+                        } else {
+                            Map<String, Object> thisFormAssignmentData = new HashMap<>();
+                            thisFormAssignmentData.put(formAssignmentConfig.getTarget().getFormField(), processParam.get(formAssignmentConfig.getSource()));
+                            formAssignmentData.put(formAssignmentConfig.getTarget().getFormId(), thisFormAssignmentData);
+                        }
+
+                    }
+
+                    vo.setFormAssignmentData(formAssignmentData);
+
+                }
+
+
+                List<Map<String, Object>> otherProcessApproveRecord = new ArrayList<>();
+
+                //此流程 是否有主流程  如果有 代表他是某个流程的子流程
+                if (StrUtil.isNotBlank(superProcessInstanceId)) {
+
+                    HistoricVariableInstance historicVariableInstance = historyService.createHistoricVariableInstanceQuery().processInstanceId(superProcessInstanceId).variableName(WorkflowConstant.PROCESS_SCHEMA_NAME_KEY).singleResult();
+                    //获取主流程审批记录
+                    List<ProcessRecordListVo> processRecordListVos = getProcessRecordListVos(superProcessInstanceId, 0);
+
+                    Map<String, Object> superProcessMap = new HashMap<>();
+                    superProcessMap.put("schemaName", historicVariableInstance.getValue() + "(上级流程)");
+                    superProcessMap.put("records", processRecordListVos);
+
+                    otherProcessApproveRecord.add(superProcessMap);
+
+                }
+
+
+                if (childProcess.size() > 0) {
+                    String[] strings = childProcess.stream().map(HistoricProcessInstance::getId).toArray(String[]::new);
+
+                    List<HistoricVariableInstance> childSchemaNameVarList = historyService.createHistoricVariableInstanceQuery().processInstanceIdIn(strings).variableName(WorkflowConstant.PROCESS_SCHEMA_NAME_KEY).list();
+
+                    for (HistoricProcessInstance process : childProcess) {
+                        Optional<HistoricVariableInstance> varOp = childSchemaNameVarList.stream().filter(x -> x.getProcessInstanceId().equals(process.getId())).findFirst();
+
+                        varOp.ifPresent(schemaNameVar -> {
+                            Map<String, Object> superProcessMap = new HashMap<>();
+                            superProcessMap.put("schemaName", schemaNameVar.getValue() + "(下级流程)");
+
+                            //获取主流程审批记录
+                            List<ProcessRecordListVo> processRecordListVos = getProcessRecordListVos(schemaNameVar.getProcessInstanceId(), 0);
+                            superProcessMap.put("records", processRecordListVos);
+
+                            otherProcessApproveRecord.add(superProcessMap);
+                        });
+                    }
+                }
+                //TODO  新增返回值  返回 主/子 流程 审批记录
+
+                List<ProcessRecordListVo> recordListVos = getProcessRecordListVos(processId, 0);
+                vo.setTaskRecords(recordListVos);
+                vo.setOtherProcessApproveRecord(otherProcessApproveRecord);
+            }
+            //如果找不到 就代表  开始节点之后 就是外部流程 或者 子流程  所以 返回开始节点数据就行
+            else {
+                Optional<HistoricVariableInstance> relationTasksOp = variableInstanceList.stream().filter(x -> x.getName().equals(WorkflowConstant.RELATION_TASK_KEY)).findFirst();
+
+                //如果关联任务不为空
+                if (relationTasksOp.isPresent()) {
+                    List<LaunchRelationTaskDto> relationTasks = Convert.toList(LaunchRelationTaskDto.class, relationTasksOp.get().getValue());
+
+                    if (relationTasks != null && relationTasks.size() > 0) {
+
+                        List<Long> relationSchemaIds = relationTasks.stream().map(LaunchRelationTaskDto::getSchemaId).collect(Collectors.toList());
+
+                        LambdaQueryWrapper<WorkflowSchema> queryWrapper = new LambdaQueryWrapper<>();
+                        queryWrapper.in(WorkflowSchema::getId, relationSchemaIds);
+                        queryWrapper.select(WorkflowSchema::getId, WorkflowSchema::getName);
+                        List<WorkflowSchema> workflowSchemas = workflowSchemaMapper.selectList(queryWrapper);
+                        List<UserTaskRelationTaskVo> relationTasksVo = new ArrayList<>(workflowSchemas.size());
+
+                        for (LaunchRelationTaskDto relationTask : relationTasks) {
+                            UserTaskRelationTaskVo relationTaskVo = new UserTaskRelationTaskVo();
+                            relationTaskVo.setTaskId(relationTask.getTaskId());
+                            relationTaskVo.setSchemaId(relationTask.getSchemaId());
+                            Optional<WorkflowSchema> thisSchema = workflowSchemas.stream().filter(schema -> schema.getId().equals(relationTask.getSchemaId())).findFirst();
+                            thisSchema.ifPresent(schema -> {
+                                relationTaskVo.setSchemaName(schema.getName());
+                            });
+                            relationTasksVo.add(relationTaskVo);
+                        }
+                        vo.setRelationTasks(relationTasksVo);
+                    }
+
+                }
+
+                //如果没有用户任务  开始节点可能会有表单  查看必须显示开始节点表单数据
+                Optional<Map<String, Object>> startNodeConfig = workflowSchemaConfig.getChildNodeConfig().stream().filter(c -> c.containsValue(WorkflowConstant.START_NODE_DEFAULT_ID)).findFirst();
+
+                if (!startNodeConfig.isPresent()) {
+                    throw new MyException("找不到当前节点的配置信息!");
+                }
+
+                StartNodeConfig startEventConfig = Convert.convert(StartNodeConfig.class, startNodeConfig.get());
+
+                List<Long> formIds = startEventConfig.getFormConfigs().stream().map(FormConfig::getFormId).collect(Collectors.toList());
+                String[] formKeys = startEventConfig.getFormConfigs().stream().map(FormConfig::getKey).toArray(String[]::new);
+                List<FormTemplate> formTemplates = formTemplateMapper.selectList(Wrappers.lambdaQuery(FormTemplate.class).in(formIds.size() > 0, FormTemplate::getId, formIds));
+
+                List<HistoricVariableInstance> allFormData = historyService.createHistoricVariableInstanceQuery()
+                        .processInstanceId(processId)
+                        .variableNameIn(formKeys)
+                        .list();
+
+
+                List<UserTaskFormInfoVo> formInfoVos = new ArrayList<>(startEventConfig.getFormConfigs().size());
+                for (FormConfig formConfig : startEventConfig.getFormConfigs()) {
+
+                    UserTaskFormInfoVo formInfoVo = new UserTaskFormInfoVo();
+                    formInfoVo.setFormType(formConfig.getFormType());
+                    formInfoVo.setFormConfig(formConfig);
+
+                    if (allFormData.stream().anyMatch(x -> x.getName().equals(formConfig.getKey()))) {
+                        HistoricVariableInstance historicVariableInstance = allFormData.stream().filter(x -> x.getName().equals(formConfig.getKey())).findFirst().orElse(new HistoricVariableInstanceEntity());
+                        formInfoVo.setFormData(Convert.toMap(String.class, Object.class, historicVariableInstance.getValue()));
+                    }
+
+                    //TODO 系统表单 和 自定义表单 走同一套流程  都是使用json  以后看能否有更好的解决方案 解决用户手动修改系统表单代码
+                    if (formConfig.getFormType() == FormTemplateType.CUSTOM.getCode() || formConfig.getFormType() == FormTemplateType.SYSTEM.getCode()) {
+                        Optional<FormTemplate> templateOp = formTemplates.stream().filter(f -> Objects.equals(f.getId(), formConfig.getFormId())).findFirst();
+                        templateOp.ifPresent(t -> formInfoVo.setFormJson(t.getFormJson()));
+                    }
+
+                    formInfoVos.add(formInfoVo);
+                }
+                vo.setFormInfos(formInfoVos);
+                vo.setSchemaInfo(BeanUtil.toBean(workflowSchema, WorkflowSchemaInfoVo.class));
+
+                List<Map<String, Object>> otherProcessApproveRecord = new ArrayList<>();
+
+                //此流程 是否有主流程  如果有 代表他是某个流程的子流程
+                if (StrUtil.isNotBlank(superProcessInstanceId)) {
+
+                    HistoricVariableInstance historicVariableInstance = historyService.createHistoricVariableInstanceQuery().processInstanceId(superProcessInstanceId).variableName(WorkflowConstant.PROCESS_SCHEMA_NAME_KEY).singleResult();
+                    //获取主流程审批记录
+                    List<ProcessRecordListVo> processRecordListVos = getProcessRecordListVos(superProcessInstanceId, 0);
+
+                    Map<String, Object> superProcessMap = new HashMap<>();
+                    superProcessMap.put("schemaName", historicVariableInstance.getValue() + "(上级流程)");
+                    superProcessMap.put("records", processRecordListVos);
+
+                    otherProcessApproveRecord.add(superProcessMap);
+
+                }
+
+
+                if (childProcess.size() > 0) {
+                    String[] strings = childProcess.stream().map(HistoricProcessInstance::getId).toArray(String[]::new);
+
+                    List<HistoricVariableInstance> childSchemaNameVarList = historyService.createHistoricVariableInstanceQuery().processInstanceIdIn(strings).variableName(WorkflowConstant.PROCESS_SCHEMA_NAME_KEY).list();
+
+                    for (HistoricProcessInstance process : childProcess) {
+                        Optional<HistoricVariableInstance> varOp = childSchemaNameVarList.stream().filter(x -> x.getProcessInstanceId().equals(process.getId())).findFirst();
+
+                        varOp.ifPresent(schemaNameVar -> {
+                            Map<String, Object> superProcessMap = new HashMap<>();
+                            superProcessMap.put("schemaName", schemaNameVar.getValue() + "(下级流程)");
+
+                            //获取主流程审批记录
+                            List<ProcessRecordListVo> processRecordListVos = getProcessRecordListVos(schemaNameVar.getProcessInstanceId(), 0);
+                            superProcessMap.put("records", processRecordListVos);
+
+                            otherProcessApproveRecord.add(superProcessMap);
+                        });
+                    }
+                }
+                //TODO  新增返回值  返回 主/子 流程 审批记录
+
+                List<ProcessRecordListVo> recordListVos = getProcessRecordListVos(processId, 0);
+                vo.setTaskRecords(recordListVos);
+                vo.setOtherProcessApproveRecord(otherProcessApproveRecord);
+            }
+        }
+        //判断流程是否完全没有用户任务
+        else {
+            Optional<HistoricVariableInstance> relationTasksOp = variableInstanceList.stream().filter(x -> x.getName().equals(WorkflowConstant.RELATION_TASK_KEY)).findFirst();
+
+
+            //如果关联任务不为空
+            if (relationTasksOp.isPresent()) {
+                List<LaunchRelationTaskDto> relationTasks = Convert.toList(LaunchRelationTaskDto.class, relationTasksOp.get().getValue());
+
+                if (relationTasks != null && relationTasks.size() > 0) {
+
+                    List<Long> relationSchemaIds = relationTasks.stream().map(LaunchRelationTaskDto::getSchemaId).collect(Collectors.toList());
+
+                    LambdaQueryWrapper<WorkflowSchema> queryWrapper = new LambdaQueryWrapper<>();
+                    queryWrapper.in(WorkflowSchema::getId, relationSchemaIds);
+                    queryWrapper.select(WorkflowSchema::getId, WorkflowSchema::getName);
+                    List<WorkflowSchema> workflowSchemas = workflowSchemaMapper.selectList(queryWrapper);
+                    List<UserTaskRelationTaskVo> relationTasksVo = new ArrayList<>(workflowSchemas.size());
+
+                    for (LaunchRelationTaskDto relationTask : relationTasks) {
+                        UserTaskRelationTaskVo relationTaskVo = new UserTaskRelationTaskVo();
+                        relationTaskVo.setTaskId(relationTask.getTaskId());
+                        relationTaskVo.setSchemaId(relationTask.getSchemaId());
+                        Optional<WorkflowSchema> thisSchema = workflowSchemas.stream().filter(schema -> schema.getId().equals(relationTask.getSchemaId())).findFirst();
+                        thisSchema.ifPresent(schema -> {
+                            relationTaskVo.setSchemaName(schema.getName());
+                        });
+                        relationTasksVo.add(relationTaskVo);
+                    }
+                    vo.setRelationTasks(relationTasksVo);
+                }
+
+            }
+
+            //如果没有用户任务  开始节点可能会有表单  查看必须显示开始节点表单数据
+            Optional<Map<String, Object>> startNodeConfig = workflowSchemaConfig.getChildNodeConfig().stream().filter(c -> c.containsValue(WorkflowConstant.START_NODE_DEFAULT_ID)).findFirst();
+
+            if (!startNodeConfig.isPresent()) {
+                throw new MyException("找不到当前节点的配置信息!");
+            }
+
+            StartNodeConfig startEventConfig = Convert.convert(StartNodeConfig.class, startNodeConfig.get());
+
+            List<Long> formIds = startEventConfig.getFormConfigs().stream().map(FormConfig::getFormId).collect(Collectors.toList());
+            String[] formKeys = startEventConfig.getFormConfigs().stream().map(FormConfig::getKey).toArray(String[]::new);
+            List<FormTemplate> formTemplates = formTemplateMapper.selectList(Wrappers.lambdaQuery(FormTemplate.class).in(formIds.size() > 0, FormTemplate::getId, formIds));
+
+            List<HistoricVariableInstance> allFormData = historyService.createHistoricVariableInstanceQuery()
+                    .processInstanceId(processId)
+                    .variableNameIn(formKeys)
+                    .list();
+
+
+            List<UserTaskFormInfoVo> formInfoVos = new ArrayList<>(startEventConfig.getFormConfigs().size());
+            for (FormConfig formConfig : startEventConfig.getFormConfigs()) {
+
+                UserTaskFormInfoVo formInfoVo = new UserTaskFormInfoVo();
+                formInfoVo.setFormType(formConfig.getFormType());
+                formInfoVo.setFormConfig(formConfig);
+
+                if (allFormData.stream().anyMatch(x -> x.getName().equals(formConfig.getKey()))) {
+                    HistoricVariableInstance historicVariableInstance = allFormData.stream().filter(x -> x.getName().equals(formConfig.getKey())).findFirst().orElse(new HistoricVariableInstanceEntity());
+                    formInfoVo.setFormData(Convert.toMap(String.class, Object.class, historicVariableInstance.getValue()));
+                }
+
+                //TODO 系统表单 和 自定义表单 走同一套流程  都是使用json  以后看能否有更好的解决方案 解决用户手动修改系统表单代码
+                if (formConfig.getFormType() == FormTemplateType.CUSTOM.getCode() || formConfig.getFormType() == FormTemplateType.SYSTEM.getCode()) {
+                    Optional<FormTemplate> templateOp = formTemplates.stream().filter(f -> Objects.equals(f.getId(), formConfig.getFormId())).findFirst();
+                    templateOp.ifPresent(t -> formInfoVo.setFormJson(t.getFormJson()));
+                }
+
+                formInfoVos.add(formInfoVo);
+            }
+            vo.setFormInfos(formInfoVos);
+            vo.setSchemaInfo(BeanUtil.toBean(workflowSchema, WorkflowSchemaInfoVo.class));
+
+            List<Map<String, Object>> otherProcessApproveRecord = new ArrayList<>();
+
+            //此流程 是否有主流程  如果有 代表他是某个流程的子流程
+            if (StrUtil.isNotBlank(superProcessInstanceId)) {
+
+                HistoricVariableInstance historicVariableInstance = historyService.createHistoricVariableInstanceQuery().processInstanceId(superProcessInstanceId).variableName(WorkflowConstant.PROCESS_SCHEMA_NAME_KEY).singleResult();
+                //获取主流程审批记录
+                List<ProcessRecordListVo> processRecordListVos = getProcessRecordListVos(superProcessInstanceId, 0);
+
+                Map<String, Object> superProcessMap = new HashMap<>();
+                superProcessMap.put("schemaName", historicVariableInstance.getValue() + "(上级流程)");
+                superProcessMap.put("records", processRecordListVos);
+
+                otherProcessApproveRecord.add(superProcessMap);
+
+            }
+
+
+            if (childProcess.size() > 0) {
+                String[] strings = childProcess.stream().map(HistoricProcessInstance::getId).toArray(String[]::new);
+
+                List<HistoricVariableInstance> childSchemaNameVarList = historyService.createHistoricVariableInstanceQuery().processInstanceIdIn(strings).variableName(WorkflowConstant.PROCESS_SCHEMA_NAME_KEY).list();
+
+                for (HistoricProcessInstance process : childProcess) {
+                    Optional<HistoricVariableInstance> varOp = childSchemaNameVarList.stream().filter(x -> x.getProcessInstanceId().equals(process.getId())).findFirst();
+
+                    varOp.ifPresent(schemaNameVar -> {
+                        Map<String, Object> superProcessMap = new HashMap<>();
+                        superProcessMap.put("schemaName", schemaNameVar.getValue() + "(下级流程)");
+
+                        //获取主流程审批记录
+                        List<ProcessRecordListVo> processRecordListVos = getProcessRecordListVos(schemaNameVar.getProcessInstanceId(), 0);
+                        superProcessMap.put("records", processRecordListVos);
+
+                        otherProcessApproveRecord.add(superProcessMap);
+                    });
+                }
+            }
+            //TODO  新增返回值  返回 主/子 流程 审批记录
+
+            List<ProcessRecordListVo> recordListVos = getProcessRecordListVos(processId, 0);
+            vo.setTaskRecords(recordListVos);
+            vo.setOtherProcessApproveRecord(otherProcessApproveRecord);
+
+        }
+
+
+        return vo;
+
+    }
+
+    @Override
+    public AllRecordListVo getAllRecordInfoByProcessId(String processId) {
+        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processId).singleResult();
+        //查询当前流程是否包含父亲流程
+        String superProcessInstanceId = historicProcessInstance.getSuperProcessInstanceId();
+        //查看当前流程 是否包含子流程
+        List<HistoricProcessInstance> childProcess = historyService.createHistoricProcessInstanceQuery().superProcessInstanceId(processId).list();
+
+        AllRecordListVo vo = new AllRecordListVo();
+        List<Map<String, Object>> otherProcessApproveRecord = new ArrayList<>();
+        //此流程 是否有主流程  如果有 代表他是某个流程的子流程
+        if (StrUtil.isNotBlank(superProcessInstanceId)) {
+
+            HistoricVariableInstance historicVariableInstance = historyService.createHistoricVariableInstanceQuery().processInstanceId(superProcessInstanceId).variableName(WorkflowConstant.PROCESS_SCHEMA_NAME_KEY).singleResult();
+            //获取主流程审批记录
+            List<ProcessRecordListVo> processRecordListVos = getProcessRecordListVos(superProcessInstanceId, 1);
+
+            Map<String, Object> superProcessMap = new HashMap<>();
+            superProcessMap.put("schemaName", historicVariableInstance.getValue() + "(上级流程)");
+            superProcessMap.put("records", processRecordListVos);
+
+            otherProcessApproveRecord.add(superProcessMap);
+
+        }
+
+        if (childProcess.size() > 0) {
+            String[] strings = childProcess.stream().map(HistoricProcessInstance::getId).toArray(String[]::new);
+
+            List<HistoricVariableInstance> childSchemaNameVarList = historyService.createHistoricVariableInstanceQuery().processInstanceIdIn(strings).variableName(WorkflowConstant.PROCESS_SCHEMA_NAME_KEY).list();
+
+            for (HistoricProcessInstance process : childProcess) {
+                Optional<HistoricVariableInstance> varOp = childSchemaNameVarList.stream().filter(x -> x.getProcessInstanceId().equals(process.getId())).findFirst();
+
+                varOp.ifPresent(schemaNameVar -> {
+                    Map<String, Object> superProcessMap = new HashMap<>();
+                    superProcessMap.put("schemaName", schemaNameVar.getValue() + "(下级流程)");
+
+                    //获取主流程审批记录
+                    List<ProcessRecordListVo> processRecordListVos = getProcessRecordListVos(schemaNameVar.getProcessInstanceId(), 1);
+                    superProcessMap.put("records", processRecordListVos);
+
+                    otherProcessApproveRecord.add(superProcessMap);
+                });
+            }
+        }
+        //TODO  新增返回值  返回 主/子 流程 审批记录
+
+        List<ProcessRecordListVo> recordListVos = getProcessRecordListVos(processId, 1);
+        vo.setTaskRecords(recordListVos);
+        vo.setOtherProcessApproveRecord(otherProcessApproveRecord);
+        return vo;
+    }
+
+    @Override
+    public RecycleProcessInfoVo getRecycleProcessInfo(String processId) {
+
+        RecycleProcessInfoVo vo = new RecycleProcessInfoVo();
+
+        List<HistoricVariableInstance> list = historyService.createHistoricVariableInstanceQuery().processInstanceId(processId)
+                .variableNameLike(WorkflowConstant.PROCESS_FORMDATA_PREFIX_KEY + StringPool.PERCENT).list();
+        HistoricVariableInstance historicVariableInstance = historyService.createHistoricVariableInstanceQuery()
+                .processInstanceId(processId)
+                .variableName(WorkflowConstant.PROCESS_SCHEMA_ID_KEY).singleResult();
+
+
+        if (historicVariableInstance == null) {
+            throw new MyException("找不到当前模板id");
+
+        }
+
+        //排除xml 查出数据
+        WorkflowSchema workflowSchema = workflowSchemaMapper.selectOne(Wrappers.lambdaQuery(WorkflowSchema.class).eq(WorkflowSchema::getId, historicVariableInstance.getValue()));
+
+        //获取到整个流程模板的配置
+        WorkflowSchemaConfig workflowSchemaConfig = JSONUtil.toBean(workflowSchema.getJsonContent(), WorkflowSchemaConfig.class);
+
+        List<RelationProcessConfig> relationProcessConfig = workflowSchemaConfig.getProcessConfig().getRelationProcessConfigs();
+
+        List<Long> relationSchemaIds = relationProcessConfig.stream().map(RelationProcessConfig::getId).collect(Collectors.toList());
+
+        if (relationSchemaIds.size() > 0) {
+            LambdaQueryWrapper<WorkflowSchema> queryWrapper = new LambdaQueryWrapper<>();
+            queryWrapper.in(WorkflowSchema::getId, relationSchemaIds);
+            queryWrapper.select(WorkflowSchema::getId, WorkflowSchema::getName);
+            List<WorkflowSchema> workflowSchemas = workflowSchemaMapper.selectList(queryWrapper);
+
+            List<StartProcessRelationTaskVo> relationTasks = new ArrayList<>(workflowSchemas.size());
+            for (WorkflowSchema schema : workflowSchemas) {
+                StartProcessRelationTaskVo relationTaskVo = new StartProcessRelationTaskVo();
+                relationTaskVo.setSchemaId(schema.getId());
+                relationTaskVo.setSchemaName(schema.getName());
+                relationTasks.add(relationTaskVo);
+            }
+            vo.setRelationTasks(relationTasks);
+        }
+
+
+        Map<String, Map<String, Object>> formDatas = new HashMap<>();
+        for (HistoricVariableInstance variableInstance : list) {
+            formDatas.put(variableInstance.getName(), Convert.toMap(String.class, Object.class, variableInstance.getValue()));
+        }
+
+
+        vo.setFormDatas(formDatas);
+        vo.setSchemaInfo(BeanUtil.toBean(workflowSchema, WorkflowSchemaInfoVo.class));
+        return vo;
+    }
+
+
+    @Override
+    @SneakyThrows
+    @Transactional(rollbackFor = Exception.class)
+    public List<LaunchAndApproveVo> newLaunch(LaunchDto dto) {
+        WorkflowSchema workflowSchema = workflowSchemaMapper.selectById(dto.getSchemaId());
+
+        if (workflowSchema == null) {
+            throw new MyException("找不到此流程!");
+        }
+
+        //如果当前模板被禁用 无法发起流程
+        if (workflowSchema.getEnabledMark() == EnabledMark.DISABLED.getCode()) {
+            throw new MyException("流程被禁用!");
+        }
+
+        //获取到整个流程模板的配置
+        WorkflowSchemaConfig workflowSchemaConfig = JSONUtil.toBean(workflowSchema.getJsonContent(), WorkflowSchemaConfig.class);
+        //将工作流模板存入缓存
+        redisUtil.set(WorkflowConstant.SCHEMA_CACHE_PREFIX + workflowSchema.getId(), workflowSchema);
+
+        AuthConfig authConfig = workflowSchemaConfig.getProcessConfig().getAuthConfig();
+
+        //判断是否有发起流程的权限
+        if (!WorkFlowUtil.hasPermissions(authConfig)) {
+            throw new MyException("没有此流程权限!");
+        }
+        //获取到流程定义
+        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(workflowSchema.getDeploymentId()).singleResult();
+
+        //流程参数  发布时  存到变量中
+        List<ProcessParamConfig> processParamConfigs = workflowSchemaConfig.getProcessConfig().getProcessParamConfigs();
+
+        long count = historyService.createHistoricProcessInstanceQuery().count();
+        Map<String, Object> processParam = WorkFlowUtil.getProcessParam(processParamConfigs, workflowSchema, count + 1, null);
+
+        //表单赋值
+//        initFormAssignment(dto.getFormData(), workflowSchema, workflowSchemaConfig, processParam);
+
+        //构建流程默认参数 (全局变量 发起人id、发起人名、模板id 、模板名、页面配置参数值、流水号)等
+        VariableMap variableMap = initDefaultParam(workflowSchema, processParam, count);
+        FormTemplate formTemplate = formTemplateMapper.selectById(workflowSchema.getFormId());
+
+        //根据规则生成流程名称
+        String processName = WorkFlowUtil.generatorProcessName(workflowSchema, workflowSchemaConfig, count + 1, dto);
+        //根据规则生成流程名称
+        variableMap.putValue(WorkflowConstant.PROCESS_NAME, processName);
+
+        Optional<Map<String, Object>> startNodeMap = workflowSchemaConfig.getChildNodeConfig().stream().filter(x -> x.containsValue(WorkflowConstant.BPMN_XML_START_EVENT_TYPE_NAME)).findFirst();
+
+        if (!startNodeMap.isPresent()) {
+            throw new MyException("当前任务没有开始节点");
+        }
+
+        //如果关联任务不为空 并且有数据
+        if (dto.getRelationTasks() != null && dto.getRelationTasks().size() > 0) {
+            variableMap.putValue(WorkflowConstant.RELATION_TASK_KEY, dto.getRelationTasks());
+        }
+
+
+        //将map 转为 java类
+        StartNodeConfig startNodeConfig = Convert.convert(StartNodeConfig.class, startNodeMap.get());
+
+        //定义sessionList  存储所有表提交的session  用于最后提交commit  保证事务
+        List<Session> sessionList = new ArrayList<>(dto.getFormData().size());
+
+        //定义map 用于存储 formId以及 主键keyValue {formId:keyValue}
+//        Map<String, Long> keyValueMap = new HashMap<>(dto.getFormData().size());
+
+        List<WorkflowFormRelation> relations = new ArrayList<>(dto.getFormData().size());
+
+        //提交表单数据  在发起任务之前  原因
+        //  1、需要提交数据之后的主键数据也塞入到map中
+        //  2、有可能流程图 开始节点之后就是网关 需要提前配置好网关的流转条件  需要提前配置好变量才能发起流程  不然影响流程走向
+        //  3、功能页面发起 数据会自带主键  需要调用更新接口
+        for (FormConfig formConfig : startNodeConfig.getFormConfigs()) {
+            Map<String, Object> thisFormData = dto.getFormData().get(formConfig.getKey());
+
+
+            //如果其中某一个事务出错,所有表单提交全部回滚
+            //formData 新增之后 会将主键加入到 map  所以不需要管
+            try {
+
+                //如果提交过 默认是update
+                FormExecuteWorkflowUpdateDto executeWorkflowUpdateDto = new FormExecuteWorkflowUpdateDto();
+                executeWorkflowUpdateDto.setFormId(formConfig.getFormId());
+                executeWorkflowUpdateDto.setFormData(thisFormData);
+                variableMap.putValue(formConfig.getKey(), thisFormData);
+
+                Triple<Session, Boolean, Long> sessionLongLongTriple = formExecuteService.workflowAddOrUpdate(executeWorkflowUpdateDto);
+
+                sessionList.add(sessionLongLongTriple.getLeft());
+
+                WorkflowFormRelation formRelation = new WorkflowFormRelation();
+                formRelation.setFormId(formConfig.getFormId());
+                formRelation.setFormKey(formConfig.getKey());
+                formRelation.setFormKeyValue(sessionLongLongTriple.getRight().toString());
+
+                relations.add(formRelation);
+            } catch (Exception e) {
+                log.error("提交表单数据失败(newLaunch):",e);
+                for (Session session : sessionList) {
+                    session.quietRollback();
+                }
+                throw new MyException("【表单id: " + formConfig.getFormId() + "】 提交错误, 请联系管理员!");
+            }
+
+        }
+
+        //将formid 以及 表单主键 存储到变量中
+//        variableMap.putValue(WorkflowConstant.PROCESS_FOMRID_KEYVALUE_KEY, keyValueMap);
+
+        //如果没有报错  所有表单提交事务 一起提交  提交有错误 也统一回滚
+
+
+        try {
+            //表单提交完毕后 发起流程
+            ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinition.getId(), variableMap);
+
+            List<Task> list = taskService.createTaskQuery().processInstanceId(processInstance.getId()).list();
+
+//            List<LaunchAndApproveVo> result = isPrevChooseApprove(workflowSchemaConfig, list, variableMap);
+
+            //如果不需要指定审批人 默认走自动同意规则
+            invokeAutoAgree(processInstance.getId(), workflowSchema.getId(), workflowSchemaConfig, list);
+
+            //重新获取任务节点,判断是否需要指定下一审批人
+            list = taskService.createTaskQuery().processInstanceId(processInstance.getId()).list();
+
+            List<LaunchAndApproveVo> result = isPrevChooseApprove(workflowSchemaConfig, list, variableMap);
+
+            updateFileInfo(dto.getFileFolderIds(), processInstance.getId());
+
+            //保存 流程 表单 关联 数据
+            for (WorkflowFormRelation relation : relations) {
+                relation.setProcessId(processInstance.getId());
+            }
+
+            formRelationService.saveBatch(relations);
+
+            for (Session session : sessionList) {
+                session.getConnection().setAutoCommit(Boolean.FALSE);
+                session.commit();
+                session.close();
+            }
+
+            return result;
+        } catch (Exception e) {
+            for (Session session : sessionList) {
+                session.quietRollback();
+            }
+            if (ObjectUtil.isNotEmpty(e.getMessage()) && e.getMessage().contains("sequence flow")) {
+                throw new MyException("流转条件错误,请检查流转条件设置!");
+            } else {
+                throw new MyException("表单提交错误, 请联系系统管理员!");
+            }
+        }
+
+    }
+
+    @Override
+    @SneakyThrows
+    @Transactional(rollbackFor = Exception.class)
+    public List<LaunchAndApproveVo> reLaunch(ReLaunchDto dto) {
+
+
+        WorkflowSchema workflowSchema = workflowSchemaMapper.selectById(dto.getSchemaId());
+
+        if (workflowSchema == null) {
+            throw new MyException("找不到此流程!");
+        }
+
+        //如果当前模板被禁用 无法发起流程
+        if (workflowSchema.getEnabledMark() == EnabledMark.DISABLED.getCode()) {
+            throw new MyException("流程被禁用!");
+        }
+
+
+        //获取到整个流程模板的配置
+        WorkflowSchemaConfig workflowSchemaConfig = JSONUtil.toBean(workflowSchema.getJsonContent(), WorkflowSchemaConfig.class);
+        //将工作流模板存入缓存
+        redisUtil.set(WorkflowConstant.SCHEMA_CACHE_PREFIX + workflowSchema.getId(), workflowSchema);
+
+        AuthConfig authConfig = workflowSchemaConfig.getProcessConfig().getAuthConfig();
+
+        //判断是否有发起流程的权限
+        if (!WorkFlowUtil.hasPermissions(authConfig)) {
+            throw new MyException("没有此流程权限!");
+        }
+
+        //获取到流程定义
+        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(workflowSchema.getDeploymentId()).singleResult();
+
+        //流程参数  发布时  存到变量中
+        List<ProcessParamConfig> processParamConfigs = workflowSchemaConfig.getProcessConfig().getProcessParamConfigs();
+
+        long count = historyService.createHistoricProcessInstanceQuery().count();
+
+        Map<String, Object> processParam = WorkFlowUtil.getProcessParam(processParamConfigs, workflowSchema, count + 1, null);
+
+        //表单赋值
+//        initFormAssignment(dto.getFormData(), workflowSchema, workflowSchemaConfig, processParam);
+
+        //构建流程默认参数 (全局变量 发起人id、发起人名、模板id 、模板名、页面配置参数值、流水号)等
+        VariableMap variableMap = initDefaultParam(workflowSchema, processParam, count);
+
+        //根据规则生成流程名称
+        String processName = WorkFlowUtil.generatorProcessName(workflowSchema, workflowSchemaConfig, count + 1, null);
+        //根据规则生成流程名称
+        variableMap.putValue(WorkflowConstant.PROCESS_NAME, processName);
+
+        Optional<Map<String, Object>> startNodeMap = workflowSchemaConfig.getChildNodeConfig().stream().filter(x -> x.containsValue(WorkflowConstant.BPMN_XML_START_EVENT_TYPE_NAME)).findFirst();
+
+        if (!startNodeMap.isPresent()) {
+            throw new MyException("当前任务没有开始节点");
+        }
+
+        //如果关联任务不为空 并且有数据
+        if (dto.getRelationTasks() != null && dto.getRelationTasks().size() > 0) {
+            variableMap.putValue(WorkflowConstant.RELATION_TASK_KEY, dto.getRelationTasks());
+        }
+
+        //将map 转为 java类
+        StartNodeConfig startNodeConfig = Convert.convert(StartNodeConfig.class, startNodeMap.get());
+
+        //定义sessionList  存储所有表提交的session  用于最后提交commit  保证事务
+        List<Session> sessionList = new ArrayList<>(dto.getFormData().size());
+
+        //定义map 用于存储 formId以及 主键keyValue {formId:keyValue}
+//        Map<String, Long> keyValueMap = new HashMap<>(dto.getFormData().size());
+
+        List<WorkflowFormRelation> relations = new ArrayList<>(dto.getFormData().size());
+
+        //提交表单数据  在发起任务之前  原因
+        //  1、需要提交数据之后的主键数据也塞入到map中
+        //  2、有可能流程图 开始节点之后就是网关 需要提前配置好网关的流转条件  需要提前配置好变量才能发起流程  不然影响流程走向
+        //  3、功能页面发起 数据会自带主键  需要调用更新接口
+        for (FormConfig formConfig : startNodeConfig.getFormConfigs()) {
+            Map<String, Object> thisFormData = dto.getFormData().get(formConfig.getKey());
+
+
+            //如果其中某一个事务出错,所有表单提交全部回滚
+            //formData 新增之后 会将主键加入到 map  所以不需要管
+            try {
+
+                //如果提交过 默认是update
+                FormExecuteWorkflowUpdateDto executeWorkflowUpdateDto = new FormExecuteWorkflowUpdateDto();
+                executeWorkflowUpdateDto.setFormId(formConfig.getFormId());
+                executeWorkflowUpdateDto.setFormData(thisFormData);
+                variableMap.putValue(formConfig.getKey(), thisFormData);
+
+                Triple<Session, Boolean, Long> sessionLongLongTriple = formExecuteService.workflowAddOrUpdate(executeWorkflowUpdateDto);
+
+                sessionList.add(sessionLongLongTriple.getLeft());
+
+                WorkflowFormRelation formRelation = new WorkflowFormRelation();
+                formRelation.setFormId(formConfig.getFormId());
+                formRelation.setFormKey(formConfig.getKey());
+                formRelation.setFormKeyValue(sessionLongLongTriple.getRight().toString());
+
+                relations.add(formRelation);
+            } catch (Exception e) {
+                log.error("提交表单数据失败(reLaunch):",e);
+                for (Session session : sessionList) {
+                    session.quietRollback();
+                }
+                throw new MyException("【表单id: " + formConfig.getFormId() + "】 提交错误, 请联系管理员!");
+            }
+
+        }
+
+        //将formid 以及 表单主键 存储到变量中
+//        variableMap.putValue(WorkflowConstant.PROCESS_FOMRID_KEYVALUE_KEY, keyValueMap);
+
+        //如果没有报错  所有表单提交事务 一起提交  提交有错误 也统一回滚
+
+
+        try {
+
+            //表单提交完毕后 发起流程
+            ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinition.getId(), variableMap);
+
+            List<Task> list = taskService.createTaskQuery().processInstanceId(processInstance.getId()).list();
+
+            List<LaunchAndApproveVo> result = isPrevChooseApprove(workflowSchemaConfig, list, variableMap);
+
+            //如果不需要指定审批人 默认走自动同意规则
+            invokeAutoAgree(processInstance.getId(), workflowSchema.getId(), workflowSchemaConfig, list);
+
+            updateFileInfo(dto.getFileFolderIds(), processInstance.getId());
+
+            //保存 流程 表单 关联 数据
+            for (WorkflowFormRelation relation : relations) {
+                relation.setProcessId(processInstance.getId());
+            }
+
+            formRelationService.saveBatch(relations);
+
+
+            for (Session session : sessionList) {
+                session.getConnection().setAutoCommit(Boolean.FALSE);
+                session.commit();
+                session.close();
+            }
+
+            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(dto.getProcessId()).singleResult();
+            List<HistoricProcessInstance> childProcessinstance = historyService.createHistoricProcessInstanceQuery().superProcessInstanceId(dto.getProcessId()).list();
+
+            for (HistoricProcessInstance processInstance1 : childProcessinstance) {
+
+                //获取到当前活动的实例
+                ActivityInstance activityInstance = runtimeService.getActivityInstance(processInstance1.getId());
+
+                //先停止当前活动示例  然后  关闭流程
+                runtimeService.createProcessInstanceModification(processInstance1.getId())
+                        .cancelActivityInstance(activityInstance.getId())
+                        .cancelAllForActivity(activityInstance.getId())
+                        .setAnnotation("【重新发起流程】")
+                        .execute();
+            }
+
+
+            //获取到当前活动的实例
+            ActivityInstance activityInstance = runtimeService.getActivityInstance(dto.getProcessId());
+
+            //如果获取不到当前活动实例  证明此流程  当前可能是在外部流程中  无需其他操作 关闭子流程 即可
+            if (activityInstance != null) {
+                runtimeService.deleteProcessInstance(dto.getProcessId(), "【重新发起流程】");
+            }
+
+            return result;
+        } catch (Exception e) {
+            for (Session session : sessionList) {
+                session.quietRollback();
+            }
+            if (e.getMessage().contains("No outgoing sequence flow")) {
+                throw new MyException("流转条件错误,请检查流转条件设置!");
+            } else {
+                throw new MyException("表单提交错误, 请联系系统管理员!");
+            }
+        }finally {
+            for (Session session : sessionList) {
+                session.close();
+            }
+        }
+
+    }
+
+
+    private void updateFileInfo(List<Long> fileFolderIds, String processId) {
+        if (fileFolderIds != null && fileFolderIds.size() > 0) {
+            File file = new File();
+            file.setProcessId(processId);
+            LambdaQueryWrapper<File> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+            lambdaQueryWrapper.in(File::getFolderId, fileFolderIds);
+            fileService.update(file, lambdaQueryWrapper);
+        }
+    }
+
+    @Override
+    public long pendingCount() {
+
+        SaSession tokenSession = StpUtil.getTokenSession();
+        User user = tokenSession.get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
+
+        TaskQuery taskQuery = taskService.createTaskQuery()
+                .active()
+                .taskVariableValueEquals(WorkflowConstant.TASK_IS_APPOINT_APPROVE, YesOrNoEnum.NO.getCode())
+                .processVariableValueEquals(WorkflowConstant.PROCESS_ISRECYCLE_FLAG_KEY, WorkflowIsRecycleType.NO.getCode())
+                .taskVariableValueLike(WorkflowConstant.TASK_ASSIGNEE_VAR_KEY, StringPool.PERCENT + user.getId() + StringPool.PERCENT);
+        return taskQuery.count();
+    }
+
+    @Override
+    public PageOutput<PendingTaskVo> pending(PendingTaskPageDto dto) {
+
+        SaSession tokenSession = StpUtil.getTokenSession();
+        User user = tokenSession.get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
+
+        TaskQuery taskQuery = taskService.createTaskQuery()
+                .active()
+                .taskVariableValueEquals(WorkflowConstant.TASK_IS_APPOINT_APPROVE, YesOrNoEnum.NO.getCode())
+                .processVariableValueEquals(WorkflowConstant.PROCESS_ISRECYCLE_FLAG_KEY, WorkflowIsRecycleType.NO.getCode())
+                .taskVariableValueLike(WorkflowConstant.TASK_ASSIGNEE_VAR_KEY, StringPool.PERCENT + user.getId() + StringPool.PERCENT);
+        //
+        if (dto.getStartTime() != null) {
+            taskQuery.taskCreatedAfter(WorkFlowUtil.getStartOfDay(dto.getStartTime()));
+        }
+        if (dto.getEndTime() != null) {
+            taskQuery.taskCreatedBefore(WorkFlowUtil.getEndOfDay(dto.getEndTime()));
+        }
+
+        if (StrUtil.isNotBlank(dto.getKeyword())) {
+            taskQuery.or()
+                    .processVariableValueLike(WorkflowConstant.PROCESS_NAME, StringPool.PERCENT + dto.getKeyword() + StringPool.PERCENT)
+                    .endOr();
+        } else {
+            if (StrUtil.isNotBlank(dto.getSerialNumber()) && StrUtil.isNumeric(dto.getSerialNumber())) {//数字类型,直接查询
+                taskQuery.processVariableValueEquals(WorkflowConstant.PROCESS_SERIAL_NUMBER_KEY, Long.valueOf(dto.getSerialNumber()));
+            }
+            if (StrUtil.isNotBlank(dto.getName())) {
+                taskQuery.processVariableValueLike(WorkflowConstant.PROCESS_SCHEMA_NAME_KEY, StringPool.PERCENT + dto.getName() + StringPool.PERCENT);
+            }
+            if (StrUtil.isNotBlank(dto.getOriginator())) {
+                taskQuery.or()
+                        .processVariableValueEquals(WorkflowConstant.PROCESS_START_USER_NAME_KEY, dto.getOriginator())
+                        .processVariableValueEquals(WorkflowConstant.PROCESS_START_USER_ID_KEY, dto.getOriginator())
+                        .endOr();
+            }
+            if (StrUtil.isNotBlank(dto.getTaskName())) {
+                taskQuery.taskNameLike(StringPool.PERCENT + dto.getTaskName() + StringPool.PERCENT);
+            }
+        }
+
+
+        long count = taskQuery.count();
+
+        List<Task> tasks = taskQuery.orderByTaskCreateTime().desc().listPage(Convert.toInt((dto.getLimit() - 1) * dto.getSize()), dto.getSize());
+
+
+        List<PendingTaskVo> result = new ArrayList<>(tasks.size());
+
+        //获取到所有taskid  去extra表一次性查出数据
+        List<String> taskIds = tasks.stream().map(Task::getId).collect(Collectors.toList());
+
+        if (taskIds.size() > 0) {
+
+            List<WorkflowExtra> workflowExtras = workflowExtraMapper.selectList(Wrappers.lambdaQuery(WorkflowExtra.class).in(WorkflowExtra::getTaskId, taskIds));
+            for (Task task : tasks) {
+                PendingTaskVo vo = new PendingTaskVo();
+                Optional<WorkflowExtra> extra = workflowExtras.stream().filter(x -> x.getTaskId().equals(task.getId())).findFirst();
+                extra.ifPresent(x -> {
+                    vo.setId(x.getId());
+                    vo.setSerialNumber(x.getSerialNumber());
+                    vo.setSchemaName(x.getSchemaName());
+                    vo.setStartUserName(x.getStartUserName());
+                    vo.setSchemaId(x.getSchemaId());
+                    vo.setSerialNumber(x.getSerialNumber());
+                    vo.setCurrentProgress(x.getCurrentProgress());
+                    vo.setProcessName(x.getProcessName());
+                });
+                vo.setProcessId(task.getProcessInstanceId());
+                vo.setTaskId(task.getId());
+                vo.setTaskName(task.getName());
+                vo.setStartTime(DateUtil.toLocalDateTime(task.getCreateTime()));
+                result.add(vo);
+            }
+        }
+        if (StrUtil.isNotBlank(dto.getSerialNumber()) && !StrUtil.isNumeric(dto.getSerialNumber())) {//流水号不为数字类型,直接对结果集置空
+            result.clear();
+        }
+        PageOutput<PendingTaskVo> output = new PageOutput<>();
+        output.setCurrentPage(dto.getLimit());
+        output.setPageSize(dto.getSize());
+        output.setTotal(Convert.toInt(count));
+        output.setList(result);
+        return output;
+    }
+
+    @Override
+    public Page<PendingTaskVo> myExamine(Page<PendingTaskVo> page, MyExaminePageDto dto) {
+        //获取登录者信息
+        SaSession tokenSession = StpUtil.getTokenSession();
+        User user = tokenSession.get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
+        List<String> taskIds = new ArrayList<>();
+        List<WorkflowApproveRecord> list = approveRecordService.list(
+            new QueryWrapper<WorkflowApproveRecord>().lambda()
+            .eq(WorkflowApproveRecord::getApproveUserId, user.getId())
+        );
+        taskIds = list.stream().map(WorkflowApproveRecord::getTaskId).collect(Collectors.toList());
+//        if(dto.getStatus() != null && dto.getStatus() == 1){
+//
+//        }else if(dto.getStatus() != null && dto.getStatus() == 0){
+//            TaskQuery taskQuery = taskService.createTaskQuery()
+//                    .active()
+//                    .taskVariableValueEquals(WorkflowConstant.TASK_IS_APPOINT_APPROVE, YesOrNoEnum.NO.getCode())
+//                    .processVariableValueEquals(WorkflowConstant.PROCESS_ISRECYCLE_FLAG_KEY, WorkflowIsRecycleType.NO.getCode())
+//                    .taskVariableValueLike(WorkflowConstant.TASK_ASSIGNEE_VAR_KEY, StringPool.PERCENT + user.getId() + StringPool.PERCENT);
+//            //
+//            if (dto.getStartTime() != null) {
+//                taskQuery.taskCreatedAfter(WorkFlowUtil.getStartOfDay(dto.getStartTime()));
+//            }
+//            if (dto.getEndTime() != null) {
+//                taskQuery.taskCreatedBefore(WorkFlowUtil.getEndOfDay(dto.getEndTime()));
+//            }
+//
+//            if (StrUtil.isNotBlank(dto.getKeyword())) {
+//                taskQuery.or()
+//                        .processVariableValueLike(WorkflowConstant.PROCESS_NAME, StringPool.PERCENT + dto.getKeyword() + StringPool.PERCENT)
+//                        .endOr();
+//            } else {
+//                if (StrUtil.isNotBlank(dto.getSerialNumber()) && StrUtil.isNumeric(dto.getSerialNumber())) {//数字类型,直接查询
+//                    taskQuery.processVariableValueEquals(WorkflowConstant.PROCESS_SERIAL_NUMBER_KEY, Long.valueOf(dto.getSerialNumber()));
+//                }
+//                if (StrUtil.isNotBlank(dto.getName())) {
+//                    taskQuery.processVariableValueLike(WorkflowConstant.PROCESS_SCHEMA_NAME_KEY, StringPool.PERCENT + dto.getName() + StringPool.PERCENT);
+//                }
+//                if (StrUtil.isNotBlank(dto.getOriginator())) {
+//                    taskQuery.or()
+//                            .processVariableValueEquals(WorkflowConstant.PROCESS_START_USER_NAME_KEY, dto.getOriginator())
+//                            .processVariableValueEquals(WorkflowConstant.PROCESS_START_USER_ID_KEY, dto.getOriginator())
+//                            .endOr();
+//                }
+//                if (StrUtil.isNotBlank(dto.getTaskName())) {
+//                    taskQuery.taskNameLike(StringPool.PERCENT + dto.getTaskName() + StringPool.PERCENT);
+//                }
+//            }
+//
+//            List<Task> tasks = taskQuery.orderByTaskCreateTime().desc().listPage(Convert.toInt((dto.getLimit() - 1) * dto.getSize()), dto.getSize());
+//            taskIds = tasks.stream().map(Task::getId).collect(Collectors.toList());
+//        }
+        dto.setTaskIds(taskIds);
+        return xjrWorkflowExtraMapper.myApproveRecord(page, dto);
+    }
+
+
+    @Override
+    @SneakyThrows
+    @Transactional(rollbackFor = Exception.class)
+    public List<LaunchAndApproveVo> newApprove(ApproveDto dto) {
+        //根据taskid  获取任务信息
+        Task task = taskService.createTaskQuery().taskId(dto.getTaskId()).singleResult();
+
+        if (task == null) {
+            throw new MyException("找不到此任务!");
+        }
+
+        //获取当前任务变量中的  schemaId
+        Long schemaId = Convert.toLong(taskService.getVariable(task.getId(), WorkflowConstant.PROCESS_SCHEMA_ID_KEY));
+
+        //排除xml 查出数据
+        WorkflowSchema workflowSchema = workflowSchemaMapper.selectOne(Wrappers.lambdaQuery(WorkflowSchema.class).eq(WorkflowSchema::getId, schemaId).select(x -> !x.getProperty().startsWith(DB_FIELD_XML_PREFIX)));
+
+//        //获取工作流配置信息
+//        WorkflowSchema workflowSchema = workflowSchemaMapper.selectById(schemaId);
+        //获取到整个流程模板的配置
+        WorkflowSchemaConfig workflowSchemaConfig = JSONUtil.toBean(workflowSchema.getJsonContent(), WorkflowSchemaConfig.class);
+        //找到当前用户任务节点的配置信息
+        Optional<Map<String, Object>> userTaskMapOptional = workflowSchemaConfig.getChildNodeConfig().stream().filter(x -> x.containsValue(task.getTaskDefinitionKey())).findFirst();
+        //判断是否找得到此任务节点 没有则报错
+        if (!userTaskMapOptional.isPresent()) {
+            throw new MyException("【任务id :" + task.getId() + "】 用户任务节点配置有误,请联系管理员!");
+        }
+
+        //将map 转为 java类
+        UserTaskConfig userTaskConfig = Convert.convert(UserTaskConfig.class, userTaskMapOptional.get());
+
+        //判断 如果有开启签章  就判断签章 和 密码是否正确
+        if (userTaskConfig.getOpinionConfig().getEnabled() && userTaskConfig.getOpinionConfig().getSignature() == YesOrNoEnum.YES.getCode() && ObjectUtil.isNotNull(dto.getStampId())) {
+            Stamp stamp = stampService.getById(dto.getStampId());
+            if (ObjectUtil.isNull(stamp)) {
+                throw new MyException("找不到此签章!");
+            }
+            if (!StrUtil.equals(stamp.getPassword(), dto.getStampPassword())) {
+                throw new MyException("签章密码错误!");
+            }
+        }
+
+        //查出所有表单数据
+        VariableMap variableMap = Variables.createVariables();
+
+        //查出所有表单数据
+        List<VariableInstance> allFormVar = runtimeService.createVariableInstanceQuery()
+                .processInstanceIdIn(task.getProcessInstanceId())
+                .variableNameLike(WorkflowConstant.PROCESS_FORMDATA_PREFIX_KEY + StringPool.PERCENT)
+                .list();
+
+        for (VariableInstance variableInstance : allFormVar) {
+            variableMap.putValue(variableInstance.getName(), variableInstance.getValue());
+        }
+
+        //定义sessionList  存储所有表提交的session  用于最后提交commit  保证事务
+        List<Session> sessionList = new ArrayList<>(userTaskConfig.getFormConfigs().size());
+
+        //获取流程变量的值
+        Object variable = runtimeService.getVariable(task.getProcessInstanceId(), WorkflowConstant.PROCESS_PARAM_KEY);
+
+        Map<String, Object> processParam = Convert.toMap(String.class, Object.class, variable);
+//        WorkFlowUtil.invokeFormAssignment(dto.getFormData(), userTaskConfig.getAssignmentConfig(), userTaskConfig.getFormConfigs(), processParam);
+
+        //获取到整个流程已经新增过的表单数据
+//        Object keyValueMapObject = runtimeService.getVariable(task.getProcessInstanceId(), WorkflowConstant.PROCESS_FOMRID_KEYVALUE_KEY);
+//        Map<String, Long> keyValueMap = Convert.toMap(String.class, Long.class, keyValueMapObject);
+//        if (keyValueMap == null) {
+//            keyValueMap = new HashMap<>();
+//        }
+
+        ButtonConfig buttonConfig = userTaskConfig.getButtonConfigs().stream().filter(b -> b.getButtonCode().equals(dto.getApprovedResult())).findFirst().orElse(new ButtonConfig());
+
+        //如果是其他按钮
+        if (dto.getApprovedType() == WorkflowApproveType.OTHER.getCode()) {
+
+            //如果是执行api
+            if (buttonConfig.getButtonType() == 2) {
+                ApiConfig apiConfig = buttonConfig.getApiConfig();
+                IMagicApiService magicApiService = SpringUtil.getBean(IMagicApiService.class);
+                MagicAPIService magicAPIService = SpringUtil.getBean(MagicAPIService.class);
+
+                Object varObj = runtimeService.getVariables(task.getProcessInstanceId());
+                Map<String, Object> varMap = Convert.toMap(String.class, Object.class, varObj);
+
+                MagicApiInfoVo info = magicApiService.info(apiConfig.getId());
+
+                Map<String, Object> params = new HashMap<>();
+
+                for (ApiRequestParamsConfig requestParamsConfig : apiConfig.getRequestParamsConfigs()) {
+                    WorkFlowUtil.initApiParams(processParam, varMap, params, requestParamsConfig);
+                }
+                for (ApiRequestParamsConfig requestHeaderConfig : apiConfig.getRequestHeaderConfigs()) {
+                    WorkFlowUtil.initApiParams(processParam, varMap, params, requestHeaderConfig);
+                }
+                for (ApiRequestParamsConfig requestBodyConfig : apiConfig.getRequestBodyConfigs()) {
+                    WorkFlowUtil.initApiParams(processParam, varMap, params, requestBodyConfig);
+                }
+                magicAPIService.execute(info.getMethod(), info.getPath(), params);
+            }
+            //如果是执行脚本
+            else {
+                Map<String, Object> param = new HashMap<>();
+                param.put("language", buttonConfig.getScriptLanguage());
+                param.put("content", buttonConfig.getScriptContent());
+                redisUtil.set(WorkflowConstant.BUTTON_EVENT_CACHE_PRE + task.getId(), param, 10);
+            }
+        }
+
+        LambdaQueryWrapper<WorkflowFormRelation> eq = Wrappers.lambdaQuery(WorkflowFormRelation.class).eq(WorkflowFormRelation::getProcessId, task.getProcessInstanceId());
+        List<WorkflowFormRelation> formRelationList = formRelationService.list(eq);
+        List<WorkflowFormRelation> newFormRelationList = new ArrayList<>();
+
+        List<LaunchAndApproveVo> result = new ArrayList<>();
+
+        try {
+            for (FormConfig formConfig : userTaskConfig.getFormConfigs()) {
+
+                Map<String, Object> formData = dto.getFormData().get(formConfig.getKey());
+                variableMap.putValue(formConfig.getKey(), formData);
+
+                //判断此表单是否已经提交过
+
+                if (formRelationList.stream().anyMatch(r -> Objects.equals(r.getFormId(), formConfig.getFormId()) && r.getFormKey().equals(formConfig.getKey()))) {
+
+                    //如果提交过 默认是update
+                    FormExecuteWorkflowUpdateDto executeWorkflowUpdateDto = new FormExecuteWorkflowUpdateDto();
+                    executeWorkflowUpdateDto.setFormId(formConfig.getFormId());
+                    executeWorkflowUpdateDto.setFormData(formData);
+
+                    Triple<Session, Long, Long> sessionLongLongTriple = formExecuteService.workflowUpdate(executeWorkflowUpdateDto);
+                    //如果是已经提交过的表单 变量keyValueMap 已经存在 没有必要在新增
+                    sessionList.add(sessionLongLongTriple.getLeft());
+
+                } else {
+                    //如果没有提交过 默认是add
+                    FormExecuteWorkflowAddDto executeWorkflowAddDto = new FormExecuteWorkflowAddDto();
+                    executeWorkflowAddDto.setFormId(formConfig.getFormId());
+                    executeWorkflowAddDto.setFormData(formData);
+
+                    Triple<Session, Long, Long> sessionLongLongTriple = formExecuteService.workflowAdd(executeWorkflowAddDto);
+                    sessionList.add(sessionLongLongTriple.getLeft());
+
+                    WorkflowFormRelation relation = new WorkflowFormRelation();
+                    relation.setProcessId(task.getProcessInstanceId());
+                    relation.setFormId(formConfig.getFormId());
+                    relation.setFormKey(formConfig.getKey());
+                    relation.setFormKeyValue(sessionLongLongTriple.getRight().toString());
+
+                    newFormRelationList.add(relation);
+
+//                    keyValueMap.put(formConfig.getKey(), sessionLongLongTriple.getRight());
+
+                }
+            }
+
+            formRelationService.saveBatch(newFormRelationList);
+
+            //将formid 以及 表单主键 存储到变量中
+//            variableMap.putValue(WorkflowConstant.PROCESS_FOMRID_KEYVALUE_KEY, keyValueMap);
+
+//            //----------------------------------参数赋值------------------------------------------------
+//            WorkFlowUtil.invokeParamAssignment(userTaskConfig.getAssignmentConfig(), processParam,workflowSchema);
+//
+//            variableMap.putValue(WorkflowConstant.PROCESS_PARAM_KEY, processParam);
+//
+//            //----------------------------------参数赋值------------------------------------------------
+
+            WorkFlowUtil.cacheTaskAssigneeRecord(task.getProcessInstanceId(), task.getId(), StpUtil.getLoginIdAsLong());
+
+            WorkFlowUtil.cacheTaskApproveType(task.getProcessInstanceId(), task.getId(), dto.getApprovedType());
+
+            User user = StpUtil.getTokenSession().get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
+            //将表单数据 | 流程线数据 | keyValueMap 存入变量
+            runtimeService.setVariables(task.getProcessInstanceId(), variableMap);
+
+
+            List<String> variableNames = ListUtil.toList(
+                    WorkflowConstant.PROCESS_SCHEMA_ID_KEY,
+                    WorkflowConstant.PROCESS_START_USER_ID_KEY,
+                    WorkflowConstant.PROCESS_START_USER_NAME_KEY,
+                    WorkflowConstant.PROCESS_SCHEMA_NAME_KEY,
+                    WorkflowConstant.PROCESS_SERIAL_NUMBER_KEY);
+
+            Map<String, Object> variableMaps = runtimeService.getVariables(task.getProcessInstanceId(), variableNames);
+            //如果有设置 传阅人  加入到变量中
+            String circulateMessage = "";
+            if (dto.getCirculateConfigs().size() > 0) {
+                circulateMessage = initCirculate(task, dto.getCirculateConfigs(), workflowSchemaConfig, userTaskConfig, variableMaps);
+            }
+
+
+            //任务设置审批意见
+            taskService.createComment(task.getId(), task.getProcessInstanceId(), dto.getApprovedContent());
+
+
+            //新增任务审批记录
+            WorkflowApproveRecord approveRecord = new WorkflowApproveRecord();
+            approveRecord.setSchemaId(schemaId);
+            approveRecord.setCurrentProgress(userTaskConfig.getCurrentProgress());
+            approveRecord.setSerialNumber(MapUtil.getLong(variableMaps, WorkflowConstant.PROCESS_SERIAL_NUMBER_KEY));
+            approveRecord.setApproveComment(dto.getApprovedContent());
+            approveRecord.setApproveTime(LocalDateTime.now());
+            approveRecord.setApproveUserId(StpUtil.getLoginIdAsLong());
+            approveRecord.setApproveStamp(dto.getStampId());
+            approveRecord.setProcessId(task.getProcessInstanceId());
+            approveRecord.setTaskId(task.getId());
+            approveRecord.setTaskDefinitionKey(task.getTaskDefinitionKey());
+            approveRecord.setTaskName(task.getName());
+            approveRecord.setStartUserId(MapUtil.getLong(variableMaps, WorkflowConstant.PROCESS_START_USER_ID_KEY));
+            approveRecord.setApproveUserPostId(user.getPostId());
+            approveRecord.setApproveType(dto.getApprovedType());
+            approveRecord.setApproveResult(buttonConfig.getButtonName());
+
+            approveRecordService.save(approveRecord);
+
+            WorkflowExtra extra = new WorkflowExtra();
+            extra.setEndTime(LocalDateTime.now());
+            extraService.update(extra, Wrappers.lambdaQuery(WorkflowExtra.class).eq(WorkflowExtra::getTaskId, dto.getTaskId()));
+
+            String resultVarName = task.getTaskDefinitionKey() +
+                    StringPool.UNDERSCORE + StringPool.UNDERSCORE + StringPool.UNDERSCORE +
+                    WorkflowConstant.BUTTON_APPROVE_VAR_FLAG +
+                    StringPool.UNDERSCORE + StringPool.UNDERSCORE + StringPool.UNDERSCORE +
+                    WorkflowConstant.BUTTON_APPROVE_RESULT_VAR_FLAG;
+
+            //审批所选按钮需要保存到变量表中  因为流程线可能用上
+            // 先判断是否为会签节点  如果是会签节点 变量数据 会有审批结果
+            //  审批结果
+            if (userTaskConfig.getCountersignConfig().getMultipleInstancesType() == WorkflowMultiInstanceType.NONE.getCode()) {
+                String buttonVarName = task.getTaskDefinitionKey() + StringPool.UNDERSCORE + StringPool.UNDERSCORE + StringPool.UNDERSCORE + WorkflowConstant.BUTTON_APPROVE_VAR_FLAG;
+                runtimeService.setVariable(task.getProcessInstanceId(), buttonVarName, dto.getApprovedResult());
+            } else {
+                String agreeButtonVarName = task.getTaskDefinitionKey() +
+                        StringPool.UNDERSCORE + StringPool.UNDERSCORE + StringPool.UNDERSCORE +
+                        WorkflowConstant.BUTTON_APPROVE_VAR_FLAG +
+                        StringPool.UNDERSCORE + StringPool.UNDERSCORE + StringPool.UNDERSCORE +
+                        WorkflowConstant.BUTTON_AGREE_APPROVE_VAR_FLAG;
+
+                String rejectButtonVarName = task.getTaskDefinitionKey() +
+                        StringPool.UNDERSCORE + StringPool.UNDERSCORE + StringPool.UNDERSCORE +
+                        WorkflowConstant.BUTTON_APPROVE_VAR_FLAG +
+                        StringPool.UNDERSCORE + StringPool.UNDERSCORE + StringPool.UNDERSCORE +
+                        WorkflowConstant.BUTTON_REJECT_APPROVE_VAR_FLAG;
+
+                //如果是点击的同意  默认查询同意 总和 如果有 就 +1  如果没有 设置为1
+                if (dto.getApprovedType() == WorkflowApproveType.AGREE.getCode()) {
+                    Object agreeObj = runtimeService.getVariable(task.getProcessInstanceId(), agreeButtonVarName);
+                    int nowAgreeCount = Convert.toInt(agreeObj) + 1;
+                    runtimeService.setVariable(task.getProcessInstanceId(), agreeButtonVarName, nowAgreeCount);
+
+
+                    //如果是全部 需要全部同意
+                    if (userTaskConfig.getCountersignConfig().getFinishType() == WorkflowMultiInstanceFinishType.ALL.getCode()) {
+                        Object nrOfInstances = runtimeService.getVariable(task.getExecutionId(), WorkflowConstant.MULTI_INSTANCE_VAR_KEY);
+                        if (Objects.equals(nowAgreeCount, Convert.toInt(nrOfInstances))) {
+                            runtimeService.setVariable(task.getProcessInstanceId(), resultVarName, Boolean.TRUE);
+                        }
+                    }
+
+                    //如果是单个 代码只要能执行到此处 就代表已经会签通过了
+                    if (userTaskConfig.getCountersignConfig().getFinishType() == WorkflowMultiInstanceFinishType.SINGLE.getCode()) {
+                        runtimeService.setVariable(task.getProcessInstanceId(), resultVarName, Boolean.TRUE);
+                    }
+
+                    //如果是百分比
+                    if (userTaskConfig.getCountersignConfig().getFinishType() == WorkflowMultiInstanceFinishType.PERCENTAGE.getCode()) {
+                        Object nrOfInstances = runtimeService.getVariable(task.getExecutionId(), WorkflowConstant.MULTI_INSTANCE_VAR_KEY);
+
+                        //判断是否达到百分比
+                        if ((Convert.toDouble(nowAgreeCount) / Convert.toDouble(nrOfInstances) * 100) > Convert.toDouble(userTaskConfig.getCountersignConfig().getPercentage())) {
+                            runtimeService.setVariable(task.getProcessInstanceId(), resultVarName, Boolean.TRUE);
+                        }
+
+                    }
+
+                } else {
+                    Object rejectObj = runtimeService.getVariable(task.getProcessInstanceId(), rejectButtonVarName);
+                    int nowRejectCount = Convert.toInt(rejectObj) + 1;
+                    runtimeService.setVariable(task.getProcessInstanceId(), rejectButtonVarName, nowRejectCount);
+
+                    //如果是全部 需要全部同意 只要代码进入这里 就代表  已经 会签不通过
+                    if (userTaskConfig.getCountersignConfig().getFinishType() == WorkflowMultiInstanceFinishType.ALL.getCode()) {
+                        runtimeService.setVariable(task.getProcessInstanceId(), resultVarName, Boolean.FALSE);
+                    }
+                }
+
+            }
+
+            Object resultName = new Object();
+            //获取会签流程的结果,防止会签节点后面直接跟结束节点,导致拿不到流程数据
+            if (userTaskConfig.getCountersignConfig().getMultipleInstancesType() != WorkflowMultiInstanceType.NONE.getCode()) {
+                resultName = runtimeService.getVariable(task.getProcessInstanceId(), resultVarName);
+            }
+
+            //如果是同意  || 拒绝  || 其他  默认都是流程往下走
+            if (dto.getApprovedType() == WorkflowApproveType.AGREE.getCode() || dto.getApprovedType() == WorkflowApproveType.DISAGREE.getCode() || dto.getApprovedType() == WorkflowApproveType.OTHER.getCode()) {
+
+                //新增流程发起流程记录
+                WorkflowRecord record = new WorkflowRecord();
+                record.setNodeId(task.getId());
+                record.setNodeName(task.getName());
+                record.setNodeType(WorkflowConstant.USER_TASK_TYPE_NAME);
+                record.setProcessId(task.getProcessInstanceId());
+                record.setSchemaId(schemaId);
+                record.setNodeMultiType(WorkflowMultiInstanceType.NONE.getCode());
+                //时间设值必须写在complete上面,防止用户任务节点监听时的流程信息,在次任务前面。
+                record.setRecordTime(LocalDateTime.now());
+                //当前任务的名称
+                String oldTaskName = task.getName();
+                record.setCirculateMessage(circulateMessage);
+
+                taskService.complete(task.getId());
+                List<Task> list = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list();
+                result = isPrevChooseApprove(workflowSchemaConfig, list, variableMap);
+
+                //下一个节点的任务名称集合
+                List<String> nextTaskNameList = list.stream().map(Task::getName).collect(Collectors.toList());
+
+                //如果不需要指定审批人 默认走自动同意规则
+                invokeAutoAgree(task.getProcessInstanceId(), workflowSchema.getId(), workflowSchemaConfig, list);
+
+                //新增工作流程信息数据
+                addWorkflowRecord(userTaskConfig, nextTaskNameList, user, record, oldTaskName, buttonConfig.getButtonName(), dto.getApprovedContent(), task, resultName);
+
+            }
+
+            //如果是驳回
+            if (dto.getApprovedType() == WorkflowApproveType.REJECT.getCode()) {
+                //获取到当前活动的实例
+                ActivityInstance activityInstance = runtimeService.getActivityInstance(task.getProcessInstanceId());
+
+                //先停止当前活动示例  然后  测回流程到指定节点
+                runtimeService.createProcessInstanceModification(task.getProcessInstanceId())
+                        .cancelActivityInstance(activityInstance.getId())
+                        .setAnnotation("【审批人:" + user.getName() + "】 驳回 【任务:" + task.getId() + "】")
+                        .startBeforeActivity(dto.getRejectNodeActivityId())
+                        .execute();
+
+
+                Optional<Map<String, Object>> rejectNodeMap = workflowSchemaConfig.getChildNodeConfig().stream().filter(x -> x.containsValue(dto.getRejectNodeActivityId())).findFirst();
+
+                rejectNodeMap.ifPresent(node -> {
+                    //将map 转为 java类
+                    UserTaskConfig rejectUserTaskConfig = Convert.convert(UserTaskConfig.class, node);
+
+                    //新增流程发起流程记录
+                    WorkflowRecord record = new WorkflowRecord();
+                    record.setNodeId(task.getId());
+                    record.setNodeName(task.getName());
+                    record.setNodeType(WorkflowConstant.USER_TASK_TYPE_NAME);
+                    record.setProcessId(task.getProcessInstanceId());
+                    record.setSchemaId(schemaId);
+                    record.setNodeMultiType(WorkflowMultiInstanceType.NONE.getCode());
+                    record.setRecordTime(LocalDateTime.now().minusSeconds(+1));//时间设置提前1秒钟,好排序
+
+//                    record.setMessage("【审批人:" + user.getName() + "】 将 【任务:" + task.getName() + "】 驳回到 【任务:" + rejectUserTaskConfig.getName() + "】");
+                    record.setMessage("审批信息:【" + user.getName() + "】【驳回】审批,由【" + task.getName() + "】 流转到【" + rejectUserTaskConfig.getName() + "】");
+                    workflowRecordMapper.insert(record);
+                });
+
+            }
+            //如果是结束
+            if (dto.getApprovedType() == WorkflowApproveType.FINISH.getCode()) {
+                //获取到当前活动的实例
+                ActivityInstance activityInstance = runtimeService.getActivityInstance(task.getProcessInstanceId());
+
+                //先停止当前活动示例  然后  关闭流程
+                runtimeService.createProcessInstanceModification(task.getProcessInstanceId())
+                        .cancelActivityInstance(activityInstance.getId())
+                        .cancelAllForActivity(activityInstance.getId())
+                        .setAnnotation("【审批人:" + user.getName() + "】 结束 【任务:" + task.getId() + "】")
+                        .execute();
+
+                //新增流程发起流程记录
+                WorkflowRecord record = new WorkflowRecord();
+                record.setNodeId(task.getId());
+                record.setNodeName(task.getName());
+                record.setNodeType(WorkflowConstant.USER_TASK_TYPE_NAME);
+                record.setProcessId(task.getProcessInstanceId());
+                record.setSchemaId(schemaId);
+                record.setNodeMultiType(WorkflowMultiInstanceType.NONE.getCode());
+                record.setRecordTime(LocalDateTime.now());
+
+                record.setMessage("【审批人:" + user.getName() + "】 结束 【任务:" + task.getName() + "】");
+
+                workflowRecordMapper.insert(record);
+
+            }
+
+            updateFileInfo(dto.getFileFolderIds(), task.getProcessInstanceId());
+
+            for (Session session : sessionList) {
+                session.getConnection().setAutoCommit(Boolean.FALSE);
+                session.commit();
+                session.close();
+            }
+
+        } catch (Exception e) {
+            for (Session session : sessionList) {
+                session.quietRollback();
+            }
+            if (e.getMessage().contains("sequence flow")) {
+                throw new MyException("流转条件错误,请检查流转条件设置!");
+            } else {
+                throw new MyException("表单提交错误, 请联系系统管理员!");
+            }
+        }
+
+
+        return result;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public List<ApproveMultiVo> approveMulti(ApproveMultiDto dto) {
+
+        List<Task> taskList = taskService.createTaskQuery().taskIdIn(dto.getTaskIds().toArray(new String[0])).list();
+
+
+        List<String> variableNames = ListUtil.toList(
+                WorkflowConstant.PROCESS_SCHEMA_ID_KEY,
+                WorkflowConstant.PROCESS_START_USER_ID_KEY,
+                WorkflowConstant.PROCESS_START_USER_NAME_KEY,
+                WorkflowConstant.PROCESS_SCHEMA_NAME_KEY,
+                WorkflowConstant.PROCESS_SERIAL_NUMBER_KEY,
+                WorkflowConstant.PROCESS_PARAM_KEY);
+
+        List<HistoricVariableInstance> varList = historyService.createHistoricVariableInstanceQuery()
+                .processInstanceIdIn(taskList.stream().map(Task::getProcessInstanceId).toArray(String[]::new))
+                .variableNameIn(variableNames.toArray(new String[0]))
+                .list();
+
+        List<HistoricVariableInstance> formDataList = historyService.createHistoricVariableInstanceQuery()
+                .processInstanceIdIn(taskList.stream().map(Task::getProcessInstanceId).toArray(String[]::new))
+                .variableNameLike(WorkflowConstant.PROCESS_FORMDATA_PREFIX_KEY + StringPool.PERCENT)
+                .list();
+
+        List<Object> allSchemaId = varList.stream().filter(x -> x.getName().equals(WorkflowConstant.PROCESS_SCHEMA_ID_KEY)).map(HistoricVariableInstance::getValue).collect(Collectors.toList());
+
+        //排除xml 查出数据
+        List<WorkflowSchema> workflowSchemaList = workflowSchemaMapper.selectList(Wrappers.lambdaQuery(WorkflowSchema.class).in(WorkflowSchema::getId, allSchemaId).select(x -> !x.getProperty().startsWith(DB_FIELD_XML_PREFIX)));
+        User user = StpUtil.getTokenSession().get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
+
+        //定义sessionList  存储所有表提交的session  用于最后提交commit  保证事务
+        List<Session> sessionList = new ArrayList<>();
+        List<ApproveMultiVo> approveMultiVoList = new ArrayList<>();
+        try {
+            List<WorkflowExtra> workflowExtras = workflowExtraMapper.selectList(Wrappers.lambdaQuery(WorkflowExtra.class).in(WorkflowExtra::getTaskId, dto.getTaskIds()));
+            for (String taskId : dto.getTaskIds()) {
+                Task task = taskList.stream().filter(t -> t.getId().equals(taskId)).findFirst().orElse(new TaskEntity());
+                HistoricVariableInstance schemaIdInstance = varList.stream().filter(v -> v.getName().equals(WorkflowConstant.PROCESS_SCHEMA_ID_KEY) && v.getProcessInstanceId().equals(task.getProcessInstanceId())).findFirst().orElse(new HistoricVariableInstanceEntity());
+
+                //获取当前任务变量中的  schemaId
+                Long schemaId = Convert.toLong(taskService.getVariable(task.getId(), WorkflowConstant.PROCESS_SCHEMA_ID_KEY));
+
+                WorkflowSchema workflowSchema = workflowSchemaList.stream().filter(w -> w.getId().equals(Convert.toLong(schemaIdInstance.getValue()))).findFirst().orElse(new WorkflowSchema());
+                //获取到整个流程模板的配置
+                WorkflowSchemaConfig workflowSchemaConfig = JSONUtil.toBean(workflowSchema.getJsonContent(), WorkflowSchemaConfig.class);
+                //找到当前用户任务节点的配置信息
+                Optional<Map<String, Object>> userTaskMapOptional = workflowSchemaConfig.getChildNodeConfig().stream().filter(x -> x.containsValue(task.getTaskDefinitionKey())).findFirst();
+                //判断是否找得到此任务节点 没有则报错
+                if (!userTaskMapOptional.isPresent()) {
+                    throw new MyException("【任务id :" + task.getId() + "】 用户任务节点配置有误,请联系管理员!");
+                }
+
+                //将map 转为 java类
+                UserTaskConfig userTaskConfig = Convert.convert(UserTaskConfig.class, userTaskMapOptional.get());
+
+                //判断 如果有开启签章  就判断签章 和 密码是否正确
+                if (userTaskConfig.getOpinionConfig().getEnabled() && userTaskConfig.getOpinionConfig().getSignature() == YesOrNoEnum.YES.getCode() && ObjectUtil.isNotNull(dto.getStampId())) {
+                    Stamp stamp = stampService.getById(dto.getStampId());
+                    if (ObjectUtil.isNull(stamp)) {
+                        throw new MyException("找不到此签章!");
+                    }
+                    if (!StrUtil.equals(stamp.getPassword(), dto.getStampPassword())) {
+                        throw new MyException("签章密码错误!");
+                    }
+                }
+
+                HistoricVariableInstance processParamInstance = varList.stream().filter(v -> v.getName().equals(WorkflowConstant.PROCESS_PARAM_KEY) && v.getProcessInstanceId().equals(task.getProcessInstanceId())).findFirst().orElse(new HistoricVariableInstanceEntity());
+                //获取流程变量的值
+                Map<String, Object> processParam = Convert.toMap(String.class, Object.class, processParamInstance.getValue());
+
+                //获取到当前流程的所有表单数据
+                List<HistoricVariableInstance> thisTaskFormData = formDataList.stream().filter(x -> x.getProcessInstanceId().equals(task.getProcessInstanceId())).collect(Collectors.toList());
+
+                //拼凑成表单 Map<String, Map<String, Object>> 类型
+                Map<String, Map<String, Object>> allFormData = new HashMap<>();
+                VariableMap variableMap = Variables.createVariables();
+
+                for (HistoricVariableInstance variableInstance : thisTaskFormData) {
+                    allFormData.put(variableInstance.getName(), Convert.toMap(String.class, Object.class, variableInstance.getValue()));
+                }
+
+                WorkFlowUtil.invokeFormAssignment(allFormData, userTaskConfig.getAssignmentConfig(), userTaskConfig.getFormConfigs(), processParam);
+
+
+                for (FormConfig formConfig : userTaskConfig.getFormConfigs()) {
+
+                    Map<String, Object> formData = allFormData.get(formConfig.getKey());
+
+                    variableMap.putValue(formConfig.getKey(), formData);
+
+                    //表单已经提交过 默认是update
+                    FormExecuteWorkflowUpdateDto executeWorkflowUpdateDto = new FormExecuteWorkflowUpdateDto();
+                    executeWorkflowUpdateDto.setFormId(formConfig.getFormId());
+                    executeWorkflowUpdateDto.setFormData(formData);
+
+                    Triple<Session, Boolean, Long> sessionLongLongTriple = formExecuteService.workflowAddOrUpdate(executeWorkflowUpdateDto);
+                    //如果是已经提交过的表单 变量keyValueMap 已经存在 没有必要在新增
+                    sessionList.add(sessionLongLongTriple.getLeft());
+                }
+
+//                //----------------------------------参数赋值------------------------------------------------
+//                WorkFlowUtil.invokeParamAssignment(userTaskConfig.getAssignmentConfig(), processParam,workflowSchema);
+//
+//                variableMap.putValue(WorkflowConstant.PROCESS_PARAM_KEY, processParam);
+//
+//                //----------------------------------参数赋值------------------------------------------------
+
+                WorkFlowUtil.cacheTaskAssigneeRecord(task.getProcessInstanceId(), task.getId(), StpUtil.getLoginIdAsLong());
+
+                WorkFlowUtil.cacheTaskApproveType(task.getProcessInstanceId(), task.getId(), dto.getApprovedType());
+
+                //将表单数据 | 流程线数据 | keyValueMap 存入变量
+                runtimeService.setVariables(task.getProcessInstanceId(), variableMap);
+
+                //任务设置审批意见
+                taskService.createComment(task.getId(), task.getProcessInstanceId(), dto.getApprovedContent());
+
+                HistoricVariableInstance serialNumberInstance = varList.stream().filter(v -> v.getName().equals(WorkflowConstant.PROCESS_SERIAL_NUMBER_KEY) && v.getProcessInstanceId().equals(task.getProcessInstanceId())).findFirst().orElse(new HistoricVariableInstanceEntity());
+                HistoricVariableInstance startUserIdInstance = varList.stream().filter(v -> v.getName().equals(WorkflowConstant.PROCESS_START_USER_ID_KEY) && v.getProcessInstanceId().equals(task.getProcessInstanceId())).findFirst().orElse(new HistoricVariableInstanceEntity());
+
+                //新增任务审批记录
+                WorkflowApproveRecord approveRecord = new WorkflowApproveRecord();
+                approveRecord.setSchemaId(Convert.toLong(schemaIdInstance.getValue()));
+                approveRecord.setCurrentProgress(userTaskConfig.getCurrentProgress());
+                approveRecord.setSerialNumber(Convert.toLong(serialNumberInstance.getValue()));
+                approveRecord.setApproveComment(dto.getApprovedContent());
+                approveRecord.setApproveTime(LocalDateTime.now());
+                approveRecord.setApproveUserId(StpUtil.getLoginIdAsLong());
+                approveRecord.setApproveUserPostId(user.getPostId());
+                approveRecord.setApproveStamp(dto.getStampId());
+                approveRecord.setProcessId(task.getProcessInstanceId());
+                approveRecord.setTaskId(task.getId());
+                approveRecord.setTaskDefinitionKey(task.getTaskDefinitionKey());
+                approveRecord.setTaskName(task.getName());
+                approveRecord.setStartUserId(Convert.toLong(startUserIdInstance.getValue()));
+
+                Optional<ButtonConfig> buttonConfig = userTaskConfig.getButtonConfigs().stream().filter(b -> b.getApproveType() == dto.getApprovedType()).findFirst();
+                buttonConfig.ifPresent(button -> {
+                    approveRecord.setApproveResult(button.getButtonName());
+                });
+
+                approveRecordService.save(approveRecord);
+
+                WorkflowExtra extra = new WorkflowExtra();
+                extra.setEndTime(LocalDateTime.now());
+                extraService.update(extra, Wrappers.lambdaQuery(WorkflowExtra.class).eq(WorkflowExtra::getTaskId, taskId));
+
+                String resultVarName = task.getTaskDefinitionKey() +
+                        StringPool.UNDERSCORE + StringPool.UNDERSCORE + StringPool.UNDERSCORE +
+                        WorkflowConstant.BUTTON_APPROVE_VAR_FLAG +
+                        StringPool.UNDERSCORE + StringPool.UNDERSCORE + StringPool.UNDERSCORE +
+                        WorkflowConstant.BUTTON_APPROVE_RESULT_VAR_FLAG;
+
+                //审批所选按钮需要保存到变量表中  因为流程线可能用上
+                // 先判断是否为会签节点  如果是会签节点 变量数据 会有审批结果
+                //  审批结果
+                if (userTaskConfig.getCountersignConfig().getMultipleInstancesType() == WorkflowMultiInstanceType.NONE.getCode()) {
+                    String buttonVarName = task.getTaskDefinitionKey() + StringPool.UNDERSCORE + StringPool.UNDERSCORE + StringPool.UNDERSCORE + WorkflowConstant.BUTTON_APPROVE_VAR_FLAG;
+                    if (dto.getApprovedType() == WorkflowApproveType.AGREE.getCode()) {
+                        runtimeService.setVariable(task.getProcessInstanceId(), buttonVarName, "agree");
+                    }
+                    if (dto.getApprovedType() == WorkflowApproveType.DISAGREE.getCode()) {
+                        runtimeService.setVariable(task.getProcessInstanceId(), buttonVarName, "disagree");
+                    }
+                } else {
+                    String agreeButtonVarName = task.getTaskDefinitionKey() +
+                            StringPool.UNDERSCORE + StringPool.UNDERSCORE + StringPool.UNDERSCORE +
+                            WorkflowConstant.BUTTON_APPROVE_VAR_FLAG +
+                            StringPool.UNDERSCORE + StringPool.UNDERSCORE + StringPool.UNDERSCORE +
+                            WorkflowConstant.BUTTON_AGREE_APPROVE_VAR_FLAG;
+
+                    String rejectButtonVarName = task.getTaskDefinitionKey() +
+                            StringPool.UNDERSCORE + StringPool.UNDERSCORE + StringPool.UNDERSCORE +
+                            WorkflowConstant.BUTTON_APPROVE_VAR_FLAG +
+                            StringPool.UNDERSCORE + StringPool.UNDERSCORE + StringPool.UNDERSCORE +
+                            WorkflowConstant.BUTTON_REJECT_APPROVE_VAR_FLAG;
+
+
+                    //如果是点击的同意  默认查询同意 总和 如果有 就 +1  如果没有 设置为1
+                    if (dto.getApprovedType() == WorkflowApproveType.AGREE.getCode()) {
+                        Object agreeObj = runtimeService.getVariable(task.getProcessInstanceId(), agreeButtonVarName);
+                        int nowAgreeCount = Convert.toInt(agreeObj) + 1;
+                        runtimeService.setVariable(task.getProcessInstanceId(), agreeButtonVarName, nowAgreeCount);
+
+
+                        //如果是全部 需要全部同意
+                        if (userTaskConfig.getCountersignConfig().getFinishType() == WorkflowMultiInstanceFinishType.ALL.getCode()) {
+                            Object nrOfInstances = runtimeService.getVariable(task.getExecutionId(), WorkflowConstant.MULTI_INSTANCE_VAR_KEY);
+                            if (Objects.equals(nowAgreeCount, Convert.toInt(nrOfInstances))) {
+                                runtimeService.setVariable(task.getProcessInstanceId(), resultVarName, Boolean.TRUE);
+                            }
+                        }
+
+                        //如果是单个 代码只要能执行到此处 就代表已经会签通过了
+                        if (userTaskConfig.getCountersignConfig().getFinishType() == WorkflowMultiInstanceFinishType.SINGLE.getCode()) {
+                            runtimeService.setVariable(task.getProcessInstanceId(), resultVarName, Boolean.TRUE);
+                        }
+
+                        //如果是百分比
+                        if (userTaskConfig.getCountersignConfig().getFinishType() == WorkflowMultiInstanceFinishType.PERCENTAGE.getCode()) {
+                            Object nrOfInstances = runtimeService.getVariable(task.getExecutionId(), WorkflowConstant.MULTI_INSTANCE_VAR_KEY);
+
+                            //判断是否达到百分比
+                            if ((Convert.toDouble(nowAgreeCount) / Convert.toDouble(nrOfInstances) * 100) > Convert.toDouble(userTaskConfig.getCountersignConfig().getPercentage())) {
+                                runtimeService.setVariable(task.getProcessInstanceId(), resultVarName, Boolean.TRUE);
+                            }
+
+                        }
+
+                    } else {
+                        Object rejectObj = runtimeService.getVariable(task.getProcessInstanceId(), rejectButtonVarName);
+                        int nowRejectCount = Convert.toInt(rejectObj) + 1;
+                        runtimeService.setVariable(task.getProcessInstanceId(), rejectButtonVarName, nowRejectCount);
+
+                        //如果是全部 需要全部同意 只要代码进入这里 就代表  已经 会签不通过
+                        if (userTaskConfig.getCountersignConfig().getFinishType() == WorkflowMultiInstanceFinishType.ALL.getCode()) {
+                            runtimeService.setVariable(task.getProcessInstanceId(), resultVarName, Boolean.FALSE);
+                        }
+                    }
+
+                }
+
+                Object resultName = new Object();
+                //获取会签流程的结果,防止会签节点后面直接跟结束节点,导致拿不到流程数据
+                if (userTaskConfig.getCountersignConfig().getMultipleInstancesType() != WorkflowMultiInstanceType.NONE.getCode()) {
+                    resultName = runtimeService.getVariable(task.getProcessInstanceId(), resultVarName);
+                }
+
+                //如果是同意  || 拒绝  || 其他  默认都是流程往下走
+                if (dto.getApprovedType() == WorkflowApproveType.AGREE.getCode() || dto.getApprovedType() == WorkflowApproveType.DISAGREE.getCode() || dto.getApprovedType() == WorkflowApproveType.OTHER.getCode()) {
+
+                    taskService.complete(task.getId());
+                    List<Task> list = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list();
+                    //如果不需要指定审批人 默认走自动同意规则
+                    invokeAutoAgree(task.getProcessInstanceId(), workflowSchema.getId(), workflowSchemaConfig, list);
+
+                    //下一个节点的任务名称集合
+                    List<String> nextTaskNameList = list.stream().map(Task::getName).collect(Collectors.toList());
+
+                    //批量审批流程信息记录
+                    WorkflowRecord record = new WorkflowRecord();
+                    record.setNodeId(task.getId());
+                    record.setNodeName(task.getName());
+                    record.setNodeType(WorkflowConstant.USER_TASK_TYPE_NAME);
+                    record.setProcessId(task.getProcessInstanceId());
+                    record.setSchemaId(schemaId);
+                    record.setNodeMultiType(WorkflowMultiInstanceType.NONE.getCode());
+                    //时间设值必须写在complete上面,防止用户任务节点监听时的流程信息,在次任务前面。
+                    record.setRecordTime(LocalDateTime.now());
+
+                    //新增审批详情返回给前端
+                    ApproveMultiVo approveMultiVo = new ApproveMultiVo();
+                    WorkflowExtra extraFirst = workflowExtras.stream().filter(x -> x.getTaskId().equals(task.getId())).findFirst().orElse(new WorkflowExtra());
+                    approveMultiVo.setStartUserName(extraFirst.getStartUserName());
+                    approveMultiVo.setSchemaName(workflowSchema.getName());
+                    approveMultiVo.setCurrentNodeName(task.getName());
+                    if (dto.getApprovedType() == WorkflowApproveType.AGREE.getCode()) {
+                        //新增工作流程信息数据
+                        addWorkflowRecord(userTaskConfig, nextTaskNameList, user, record, task.getName(), "同意", dto.getApprovedContent(), task, resultName);
+
+                        if (nextTaskNameList.size() == 0) {
+                            String message = "【" + user.getName() + "】【同意】审批,审批意见为:“【" + dto.getApprovedContent() + "】”,由【" + task.getName() + "】 流转到【结束节点】";
+                            approveMultiVo.setApproveDetail(message);
+                        }
+                        //单流向
+                        if (nextTaskNameList.size() == 1) {
+                            String message = "【" + user.getName() + "】【同意】审批,审批意见为:“【" + dto.getApprovedContent() + "】”,由【" + task.getName() + "】 流转到【" + nextTaskNameList.get(0) + "】";
+                            approveMultiVo.setApproveDetail(message);
+                        }//多流向
+                        if (nextTaskNameList.size() > 1) {
+                            String message = "【" + user.getName() + "】【同意】审批,审批意见为:“【" + dto.getApprovedContent() + "】”,由【" + task.getName() + "】 流转到【" + nextTaskNameList.get(0) + "】";
+                            for (int i = 1; i < nextTaskNameList.size(); i++) {
+                                message = message + "、【" + nextTaskNameList.get(i) + "】";
+                            }
+                            approveMultiVo.setApproveDetail(message);
+                        }
+                        approveMultiVo.setApproveResult("审核成功");
+                    }
+                    if (dto.getApprovedType() == WorkflowApproveType.DISAGREE.getCode()) {
+                        //新增工作流程信息数据
+                        addWorkflowRecord(userTaskConfig, nextTaskNameList, user, record, task.getName(), "拒绝", dto.getApprovedContent(), task, resultName);
+                        if (nextTaskNameList.size() == 0) {
+                            String message = "【" + user.getName() + "】【拒绝】审批,审批意见为:“【" + dto.getApprovedContent() + "】”,由【" + task.getName() + "】 流转到【结束节点】";
+                            approveMultiVo.setApproveDetail(message);
+                        }
+                        //单流向
+                        if (nextTaskNameList.size() == 1) {
+                            String message = "【" + user.getName() + "】【拒绝】审批,审批意见为:“【" + dto.getApprovedContent() + "】”,由【" + task.getName() + "】 流转到【" + nextTaskNameList.get(0) + "】";
+                            approveMultiVo.setApproveDetail(message);
+                        }//多流向
+                        if (nextTaskNameList.size() > 1) {
+                            String message = "【" + user.getName() + "】【拒绝】审批,审批意见为:“【" + dto.getApprovedContent() + "】”,由【" + task.getName() + "】 流转到【" + nextTaskNameList.get(0) + "】";
+                            for (int i = 1; i < nextTaskNameList.size(); i++) {
+                                message = message + "、【" + nextTaskNameList.get(i) + "】";
+                            }
+                            approveMultiVo.setApproveDetail(message);
+                        }
+                        approveMultiVo.setApproveResult("审核成功");
+                    }
+                    approveMultiVoList.add(approveMultiVo);
+                }
+            }
+
+            for (Session session : sessionList) {
+                //TODO  如果审批接口 出现Can't call commit when autocommit=true 错误  也可以像这样设置解决
+                session.getConnection().setAutoCommit(false);
+                session.commit();
+                session.close();
+            }
+        } catch (Exception e) {
+            for (Session session : sessionList) {
+                session.quietRollback();
+            }
+            if (e instanceof MyException) {
+                throw (MyException) e;
+            } else if (e.getMessage().contains("No outgoing sequence flow")) {
+                throw new MyException("流转条件错误,请检查流转条件设置!");
+            } else {
+                throw new MyException("表单提交错误, 请联系系统管理员!");
+            }
+        }finally {
+            for (Session session : sessionList) {
+                session.close();
+            }
+        }
+
+
+        return approveMultiVoList;
+    }
+
+    @Override
+    public ApproveMultiInfoVo approveMultiInfo(ApproveMultiInfoDto dto) {
+        String[] taskIdArray = dto.getTaskIds().split(StringPool.COMMA);
+        List<Task> taskList = taskService.createTaskQuery().taskIdIn(taskIdArray).list();
+
+
+        List<HistoricVariableInstance> varList = historyService.createHistoricVariableInstanceQuery()
+                .processInstanceIdIn(taskList.stream().map(Task::getProcessInstanceId).toArray(String[]::new))
+                .variableName(WorkflowConstant.PROCESS_SCHEMA_ID_KEY)
+                .list();
+
+
+        List<Object> allSchemaId = varList.stream().filter(x -> x.getName().equals(WorkflowConstant.PROCESS_SCHEMA_ID_KEY)).map(HistoricVariableInstance::getValue).collect(Collectors.toList());
+
+        //排除xml 查出数据
+        List<WorkflowSchema> workflowSchemaList = workflowSchemaMapper.selectList(Wrappers.lambdaQuery(WorkflowSchema.class).in(WorkflowSchema::getId, allSchemaId).select(x -> !x.getProperty().startsWith(DB_FIELD_XML_PREFIX)));
+
+        ApproveMultiInfoVo vo = new ApproveMultiInfoVo();
+        for (String taskId : taskIdArray) {
+            Task task = taskList.stream().filter(t -> t.getId().equals(taskId)).findFirst().orElse(new TaskEntity());
+            HistoricVariableInstance schemaIdInstance = varList.stream().filter(v -> v.getName().equals(WorkflowConstant.PROCESS_SCHEMA_ID_KEY) && v.getProcessInstanceId().equals(task.getProcessInstanceId())).findFirst().orElse(new HistoricVariableInstanceEntity());
+
+            WorkflowSchema workflowSchema = workflowSchemaList.stream().filter(w -> w.getId().equals(Convert.toLong(schemaIdInstance.getValue()))).findFirst().orElse(new WorkflowSchema());
+            //获取到整个流程模板的配置
+            WorkflowSchemaConfig workflowSchemaConfig = JSONUtil.toBean(workflowSchema.getJsonContent(), WorkflowSchemaConfig.class);
+            //找到当前用户任务节点的配置信息
+            Optional<Map<String, Object>> userTaskMapOptional = workflowSchemaConfig.getChildNodeConfig().stream().filter(x -> x.containsValue(task.getTaskDefinitionKey())).findFirst();
+            //判断是否找得到此任务节点 没有则报错
+            if (!userTaskMapOptional.isPresent()) {
+                throw new MyException("【任务id :" + task.getId() + "】 用户任务节点配置有误,请联系管理员!");
+            }
+
+            //将map 转为 java类
+            UserTaskConfig userTaskConfig = Convert.convert(UserTaskConfig.class, userTaskMapOptional.get());
+
+            if (userTaskConfig.getOpinionConfig().getEnabled()) {
+                vo.setNeedStamp(Boolean.TRUE);//需要电子签章
+
+                if (userTaskConfig.getOpinionConfig().getSignature() == YesOrNoEnum.YES.getCode()) {
+                    vo.setNeedPassword(Boolean.TRUE);//需要电子签章密码
+                }
+                break;
+            }
+
+        }
+
+        return vo;
+    }
+
+
+    @Override
+    public boolean setApproveUser(ApproveUserDto dto) {
+        Object schemaId = taskService.getVariable(dto.getTaskId(), WorkflowConstant.PROCESS_SCHEMA_ID_KEY);
+
+        //获取任务信息
+        Task task = taskService.createTaskQuery().taskId(dto.getTaskId()).singleResult();
+
+        //查询下一个节点审批人 委托 数据  将被委托人加入到 审批人数据中
+        LambdaQueryWrapper<WorkflowDelegate> wrapper = Wrappers.lambdaQuery(WorkflowDelegate.class)
+                .in(WorkflowDelegate::getUserId, dto.getApprovedUsers())
+                .gt(WorkflowDelegate::getStartTime, DateUtil.parse(DateUtil.now()).toJdkDate())
+                .lt(WorkflowDelegate::getEndTime, DateUtil.parse(DateUtil.now()).toJdkDate())
+                .like(WorkflowDelegate::getSchemaIds, schemaId)
+                .select(WorkflowDelegate::getDelegateUserIds);
+
+        List<WorkflowDelegate> workflowDelegates = workflowDelegateMapper.selectList(wrapper);
+
+        if (workflowDelegates.size() > 0) {
+
+            List<String> allDelegateStr = workflowDelegates.stream().map(WorkflowDelegate::getDelegateUserIds).collect(Collectors.toList());
+
+            List<Long> allDelegateUserIds = Arrays.stream(StrUtil.join(StringPool.COMMA, allDelegateStr).split(StringPool.COMMA)).map(Convert::toLong).collect(Collectors.toList());
+            dto.getApprovedUsers().addAll(allDelegateUserIds);
+
+            //新增流程发起流程记录
+            //获取当前用户的信息
+            User user = StpUtil.getTokenSession().get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
+            //获取用户id对应的用户名
+            String allDelegateUserNames = getAllUserNamesByIds(allDelegateUserIds);
+            String message = "【" + user.getName() + "】通过【流程委托】委托【" + allDelegateUserNames + "】作为审批人";
+            //新增流程发起流程记录
+            WorkflowRecord record = new WorkflowRecord();
+            record.setRecordTime(LocalDateTime.now());
+            addProcessRecord(task, Convert.toLong(schemaId), message, record);
+        }
+        //包括
+        String allUserIds = StrUtil.join(StringPool.COMMA, dto.getApprovedUsers());
+
+        VariableMap variableMap = Variables.createVariables()
+                .putValue(WorkflowConstant.TASK_IS_APPOINT_APPROVE, YesOrNoEnum.NO.getCode())
+                .putValue(WorkflowConstant.TASK_ASSIGNEE_VAR_KEY, allUserIds);
+        taskService.setVariablesLocal(dto.getTaskId(), variableMap);
+
+        //这里不再写 发送消息的逻辑 默认使用一个 redis key 使用redis过期策略 执行发送消息的功能 解耦 偷懒
+        //每个消息默认相隔一秒 等于队列一样的逻辑
+        redisUtil.set(dto.getTaskId() + StringPool.UNDERSCORE + WorkflowConstant.TASK_IS_APPOINT_APPROVE, dto.getTaskId(), 1);
+        return true;
+    }
+
+    @Override
+    public boolean setApproveUserMulti(ApproveUserMultiDto dto) {
+        List<ApproveUserDto> approveUserList = dto.getApproveUserList();
+        if (approveUserList == null || approveUserList.size() == 0) {
+            throw new MyException("指定审批人不能为空!");
+        }
+
+        List<Long> allUser = new ArrayList<>();
+        for (ApproveUserDto approveUserDto : approveUserList) {
+            allUser.addAll(approveUserDto.getApprovedUsers());
+
+            //指定审批人、流程发起后、需记录指定的人的流转信息
+            String approveName = WorkFlowUtil.getAllUserNamesByIds(approveUserDto.getApprovedUsers());
+            //查询到对应task的流转信息,将message重新设值,将设置的审批人加入到里面,如果没有直接新增一条,所以需要先查询再修改
+            QueryWrapper<WorkflowRecord> wrapper = new QueryWrapper<WorkflowRecord>()
+                    .eq("node_id", approveUserDto.getTaskId())
+                    .like("message", "准备审批");
+            WorkflowRecord records = workflowRecordMapper.selectOne(wrapper);
+            if (ObjectUtil.isEmpty(records)) {
+                Object schemaId = taskService.getVariable(approveUserDto.getTaskId(), WorkflowConstant.PROCESS_SCHEMA_ID_KEY);
+                //获取任务信息
+                Task task = taskService.createTaskQuery().taskId(approveUserDto.getTaskId()).singleResult();
+                //新增流程发起流程记录
+                WorkflowRecord record = new WorkflowRecord();
+                record.setRecordTime(LocalDateTime.now());
+                addProcessRecord(task, Convert.toLong(schemaId), "【" + approveName + "】" + "准备审批", record);
+            } else {
+                //修改原本的流转记录
+                records.setMessage("【" + approveName + "】" + "准备审批");
+                workflowRecordMapper.updateById(records);
+            }
+        }
+
+        //查询下一个节点审批人 委托 数据  将被委托人加入到 审批人数据中
+        LambdaQueryWrapper<WorkflowDelegate> wrapper = Wrappers.lambdaQuery(WorkflowDelegate.class)
+                .in(WorkflowDelegate::getUserId, allUser)
+                .gt(WorkflowDelegate::getStartTime, DateUtil.parse(DateUtil.now()).toJdkDate())
+                .lt(WorkflowDelegate::getEndTime, DateUtil.parse(DateUtil.now()).toJdkDate())
+                .like(WorkflowDelegate::getSchemaIds, dto.getSchemaId())
+                .select(WorkflowDelegate::getDelegateUserIds);
+
+        List<WorkflowDelegate> workflowDelegates = workflowDelegateMapper.selectList(wrapper);
+
+        int i = 1;
+        //获取当前用户的信息
+        User user = StpUtil.getTokenSession().get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
+        for (ApproveUserDto item : approveUserList) {
+
+            if (workflowDelegates.size() > 0) {
+                List<String> allDelegateStr = workflowDelegates.stream()
+                        .filter(d -> item.getApprovedUsers().contains(d.getUserId()))
+                        .map(WorkflowDelegate::getDelegateUserIds).collect(Collectors.toList());
+                List<Long> allDelegateUserIds = Arrays.stream(StrUtil.join(StringPool.COMMA, allDelegateStr).split(StringPool.COMMA)).map(Convert::toLong).collect(Collectors.toList());
+                item.getApprovedUsers().addAll(allDelegateUserIds);
+
+                //新增流程发起流程记录
+                //获取用户id对应的用户名
+                String allDelegateUserNames = getAllUserNamesByIds(allDelegateUserIds);
+                String message = "【" + user.getName() + "】通过【流程委托】委托【" + allDelegateUserNames + "】作为审批人";
+                //获取任务信息
+                Task task = taskService.createTaskQuery().taskId(item.getTaskId()).singleResult();
+                //新增流程发起流程记录
+                WorkflowRecord record = new WorkflowRecord();
+                record.setRecordTime(LocalDateTime.now());
+                addProcessRecord(task, Convert.toLong(dto.getSchemaId()), message, record);
+            }
+            String userIds = StrUtil.join(StringPool.COMMA, item.getApprovedUsers());
+
+            VariableMap variableMap = Variables.createVariables()
+                    .putValue(WorkflowConstant.TASK_IS_APPOINT_APPROVE, YesOrNoEnum.NO.getCode())
+                    .putValue(WorkflowConstant.TASK_ASSIGNEE_VAR_KEY, userIds);
+
+            taskService.setVariablesLocal(item.getTaskId(), variableMap);
+            //到期未指定的任务 将变量设置为不需要指定
+            taskService.setVariableLocal(item.getTaskId(), WorkflowConstant.TASK_IS_APPOINT_APPROVE, YesOrNoEnum.NO.getCode());
+
+            //这里不再写 发送消息的逻辑 默认使用一个 redis key 使用redis过期策略 执行发送消息的功能 解耦 偷懒
+            //每个消息默认相隔一秒 等于队列一样的逻辑
+            redisUtil.set(item.getTaskId() + StringPool.UNDERSCORE + WorkflowConstant.TASK_IS_APPOINT_APPROVE, item.getTaskId(), i);
+            i++;
+        }
+        return true;
+    }
+
+    @Override
+    public PageOutput<RelationTaskPageVo> getRelationTaskPage(RelationTaskPageDto dto) {
+        //排除xml 查出数据
+        WorkflowSchema workflowSchema = workflowSchemaMapper.selectOne(Wrappers.lambdaQuery(WorkflowSchema.class).eq(WorkflowSchema::getId, dto.getSchemaId()).select(x -> !x.getProperty().startsWith(DB_FIELD_XML_PREFIX)));
+
+        //获取到整个流程模板的配置
+        WorkflowSchemaConfig workflowSchemaConfig = JSONUtil.toBean(workflowSchema.getJsonContent(), WorkflowSchemaConfig.class);
+
+        List<RelationProcessConfig> relationProcessConfigList = workflowSchemaConfig.getProcessConfig().getRelationProcessConfigs();
+
+        //获取到当前关联任务的设置  判断是 审批中 还是审批结束
+        Optional<RelationProcessConfig> thisRelationProcessOp = relationProcessConfigList.stream().filter(x -> x.getId().equals(dto.getRelationSchemaId())).findFirst();
+
+        HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery()
+                .processVariableValueEquals(WorkflowConstant.PROCESS_SCHEMA_ID_KEY, dto.getRelationSchemaId());
+
+
+        //
+        if (dto.getStartTime() != null) {
+            historicTaskInstanceQuery.startedAfter(dto.getStartTime());
+        }
+        if (dto.getEndTime() != null) {
+            historicTaskInstanceQuery.startedBefore(dto.getEndTime());
+        }
+        if (StrUtil.isNotBlank(dto.getKeyword())) {
+            historicTaskInstanceQuery.processVariableValueLike(WorkflowConstant.PROCESS_SCHEMA_NAME_KEY, StringPool.PERCENT + dto.getKeyword() + StringPool.PERCENT);
+        }
+
+        if (thisRelationProcessOp.isPresent()) {
+            //如果是需要已经审批完成的
+            if (thisRelationProcessOp.get().getProcessStatus() == YesOrNoEnum.YES.getCode()) {
+                historicTaskInstanceQuery.finished();
+            } else {
+                historicTaskInstanceQuery.unfinished();
+            }
+        }
+
+        //如果是查询发起人自己的
+        Optional<RelationProcessConfig> relationProcessConfigOptional = relationProcessConfigList.stream().filter(x -> x.getId().equals(dto.getRelationSchemaId())).findFirst();
+
+        relationProcessConfigOptional.ifPresent(config -> {
+            if (config.getProcessAuth() == WorkflowRelationAuthType.ORIGINATOR.getCode()) {
+                historicTaskInstanceQuery.processVariableValueEquals(WorkflowConstant.PROCESS_START_USER_ID_KEY, StpUtil.getLoginIdAsLong());
+            }
+        });
+//        for (RelationProcessConfig relationProcessConfig : relationProcessConfigList) {
+//            if (relationProcessConfig.getProcessAuth() == WorkflowRelationAuthType.ORIGINATOR.getCode()) {
+//                taskQuery.processVariableValueEquals(WorkflowConstant.PROCESS_START_USER_ID_KEY, StpUtil.getLoginId());
+//            }
+//        }
+
+        long count = historicTaskInstanceQuery.count();
+        List<HistoricTaskInstance> historicTaskInstances = historicTaskInstanceQuery.orderByHistoricActivityInstanceStartTime().desc().listPage(Convert.toInt((dto.getLimit() - 1) * dto.getSize()), dto.getSize());
+//        List<Task> tasks = taskQuery.listPage(Convert.toInt((dto.getLimit() - 1) * dto.getSize()), dto.getSize());
+
+        List<RelationTaskPageVo> result = new ArrayList<>(historicTaskInstances.size());
+        //获取到所有taskid  去extra表一次性查出数据
+        List<String> taskIds = historicTaskInstances.stream().map(HistoricTaskInstance::getId).collect(Collectors.toList());
+
+
+        if (taskIds.size() > 0) {
+
+            List<WorkflowExtra> workflowExtras = workflowExtraMapper.selectList(Wrappers.lambdaQuery(WorkflowExtra.class).in(WorkflowExtra::getTaskId, taskIds));
+
+            for (HistoricTaskInstance task : historicTaskInstances) {
+                RelationTaskPageVo vo = new RelationTaskPageVo();
+                Optional<WorkflowExtra> extra = workflowExtras.stream().filter(x -> x.getTaskId().equals(task.getId())).findFirst();
+                extra.ifPresent(x -> {
+                    vo.setSchemaName(x.getSchemaName());
+                    vo.setOriginator(x.getStartUserName());
+                });
+                vo.setProcessId(task.getProcessInstanceId());
+                vo.setTaskName(task.getName());
+                vo.setTaskId(task.getId());
+                vo.setCreateTime(task.getStartTime());
+                result.add(vo);
+            }
+        }
+
+        PageOutput<RelationTaskPageVo> output = new PageOutput<>();
+        output.setCurrentPage(dto.getLimit());
+        output.setPageSize(dto.getSize());
+        output.setTotal(Convert.toInt(count));
+        output.setList(result);
+        return output;
+    }
+
+
+    @Override
+    public RelationTaskInfoVo getRelationTaskInfo(RelationTaskInfoDto dto) {
+        RelationTaskInfoVo vo = new RelationTaskInfoVo();
+
+        HistoricTaskInstance task = historyService.createHistoricTaskInstanceQuery().taskId(dto.getTaskId()).singleResult();
+
+//        Task task = taskService.createTaskQuery().taskId(dto.getTaskId()).singleResult();
+        HistoricVariableInstance schemaIdVar = historyService.createHistoricVariableInstanceQuery()
+                .processInstanceId(task.getProcessInstanceId())
+                .variableName(WorkflowConstant.PROCESS_SCHEMA_ID_KEY).singleResult();
+//        Object schemaId = taskService.getVariable(dto.getTaskId(), WorkflowConstant.PROCESS_SCHEMA_ID_KEY);
+
+        //排除xml 查出数据
+        WorkflowSchema workflowSchema = workflowSchemaMapper.selectOne(Wrappers.lambdaQuery(WorkflowSchema.class).eq(WorkflowSchema::getId, schemaIdVar.getValue()));
+
+        //获取到整个流程模板的配置
+        WorkflowSchemaConfig workflowSchemaConfig = JSONUtil.toBean(workflowSchema.getJsonContent(), WorkflowSchemaConfig.class);
+
+        Optional<Map<String, Object>> userNodeConfigOp = workflowSchemaConfig.getChildNodeConfig().stream().filter(c -> c.containsValue(task.getTaskDefinitionKey())).findFirst();
+
+        if (!userNodeConfigOp.isPresent()) {
+            throw new MyException("当前任务没有开始节点");
+        }
+
+        List<ProcessRecordListVo> recordListVos = getProcessRecordListVos(task.getProcessInstanceId(), 0);
+        vo.setTaskRecords(recordListVos);
+
+        //将map 转为 java类
+        UserTaskConfig userTaskConfig = Convert.convert(UserTaskConfig.class, userNodeConfigOp.get());
+
+        List<Long> formIds = userTaskConfig.getFormConfigs().stream().map(FormConfig::getFormId).collect(Collectors.toList());
+        String[] allVarKey = userTaskConfig.getFormConfigs().stream().map(FormConfig::getKey).toArray(String[]::new);
+
+        List<FormTemplate> formTemplates = formTemplateMapper.selectList(Wrappers.lambdaQuery(FormTemplate.class).in(formIds.size() > 0, FormTemplate::getId, formIds));
+
+        List<HistoricVariableInstance> formDataList = historyService.createHistoricVariableInstanceQuery().processInstanceId(task.getProcessInstanceId()).variableNameIn(allVarKey).list();
+//        Map<String, Object> allFormData = taskService.getVariables(dto.getTaskId(), allVarKey);
+
+        List<RelationFormInfoVo> formInfoVos = new ArrayList<>(userTaskConfig.getFormConfigs().size());
+        for (FormConfig formConfig : userTaskConfig.getFormConfigs()) {
+
+            RelationFormInfoVo formInfoVo = new RelationFormInfoVo();
+            formInfoVo.setFormType(formConfig.getFormType());
+            formInfoVo.setFormConfig(formConfig);
+
+            //TODO 系统表单 和 自定义表单 走同一套流程  都是使用json  以后看能否有更好的解决方案 解决用户手动修改系统表单代码
+            if (formConfig.getFormType() == FormTemplateType.CUSTOM.getCode() || formConfig.getFormType() == FormTemplateType.SYSTEM.getCode()) {
+                Optional<FormTemplate> templateOp = formTemplates.stream().filter(f -> f.getId().equals(formConfig.getFormId())).findFirst();
+                templateOp.ifPresent(t -> formInfoVo.setFormJson(t.getFormJson()));
+
+                Optional<HistoricVariableInstance> thisFormData = formDataList.stream().filter(x -> x.getName().equals(formConfig.getKey())).findFirst();
+
+                thisFormData.ifPresent(form -> {
+                    Map<String, Object> formData = Convert.toMap(String.class, Object.class, form.getValue());
+                    formInfoVo.setFormData(formData);
+                });
+
+            }
+            formInfoVos.add(formInfoVo);
+        }
+        vo.setFormInfos(formInfoVos);
+        vo.setSchemaInfo(BeanUtil.toBean(workflowSchema, WorkflowSchemaInfoVo.class));
+
+        return vo;
+    }
+
+    @Override
+    public TaskInfoVo getTaskInfo(String taskId) {
+        TaskInfoVo vo = new TaskInfoVo();
+
+        HistoricTaskInstance task = historyService.createHistoricTaskInstanceQuery().taskId(taskId).singleResult();
+
+        WorkflowExtra extra = extraService.getOne(Wrappers.lambdaQuery(WorkflowExtra.class).eq(WorkflowExtra::getTaskId, taskId).select(WorkflowExtra::getSchemaId));
+
+//        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
+//        Object schemaId = taskService.getVariable(taskId, WorkflowConstant.PROCESS_SCHEMA_ID_KEY);
+
+        //排除xml 查出数据
+        WorkflowSchema workflowSchema = workflowSchemaMapper.selectOne(Wrappers.lambdaQuery(WorkflowSchema.class).eq(WorkflowSchema::getId, extra.getSchemaId()));
+//        WorkflowSchema workflowSchema = redisUtil.get(WorkflowConstant.SCHEMA_CACHE_PREFIX + extra.getSchemaId(), WorkflowSchema.class);
+
+        //获取到整个流程模板的配置
+        WorkflowSchemaConfig workflowSchemaConfig = JSONUtil.toBean(workflowSchema.getJsonContent(), WorkflowSchemaConfig.class);
+
+        Optional<Map<String, Object>> userNodeConfigOp = workflowSchemaConfig.getChildNodeConfig().stream().filter(c -> c.containsValue(task.getTaskDefinitionKey())).findFirst();
+
+        if (!userNodeConfigOp.isPresent()) {
+            throw new MyException("当前任务没有开始节点");
+        }
+        List<ProcessRecordListVo> recordListVos = getProcessRecordListVos(task.getProcessInstanceId(), 0);
+        vo.setTaskRecords(recordListVos);
+
+        //查询任务关联任务
+        vo.setRelationTaskInfo(getRelationTaskVos(task.getProcessInstanceId()));
+
+        //将map 转为 java类
+        UserTaskConfig userTaskConfig = Convert.convert(UserTaskConfig.class, userNodeConfigOp.get());
+
+        List<Long> formIds = userTaskConfig.getFormConfigs().stream().map(FormConfig::getFormId).collect(Collectors.toList());
+        String[] allVarKey = userTaskConfig.getFormConfigs().stream().map(FormConfig::getKey).toArray(String[]::new);
+        List<FormTemplate> formTemplates = formTemplateMapper.selectList(Wrappers.lambdaQuery(FormTemplate.class).in(formIds.size() > 0, FormTemplate::getId, formIds));
+
+        List<HistoricVariableInstance> list = historyService.createHistoricVariableInstanceQuery().variableNameIn(allVarKey).list();
+//        Map<String, Object> allFormData = taskService.getVariables(taskId, allVarKey);
+
+        List<RelationFormInfoVo> formInfoVos = new ArrayList<>(userTaskConfig.getFormConfigs().size());
+        for (FormConfig formConfig : userTaskConfig.getFormConfigs()) {
+
+            RelationFormInfoVo formInfoVo = new RelationFormInfoVo();
+            formInfoVo.setFormType(formConfig.getFormType());
+            formInfoVo.setFormConfig(formConfig);
+
+            //TODO 系统表单 和 自定义表单 走同一套流程  都是使用json  以后看能否有更好的解决方案 解决用户手动修改系统表单代码
+            if (formConfig.getFormType() == FormTemplateType.CUSTOM.getCode() || formConfig.getFormType() == FormTemplateType.SYSTEM.getCode()) {
+                Optional<FormTemplate> templateOp = formTemplates.stream().filter(f -> Objects.equals(f.getId(), formConfig.getFormId())).findFirst();
+                templateOp.ifPresent(t -> formInfoVo.setFormJson(t.getFormJson()));
+
+                Optional<HistoricVariableInstance> thisFormData = list.stream().filter(x -> x.getName().equals(formConfig.getKey())).findFirst();
+
+                thisFormData.ifPresent(data -> {
+                    Map<String, Object> formData = Convert.toMap(String.class, Object.class, data.getValue());
+                    formInfoVo.setFormData(formData);
+                });
+
+            }
+
+            formInfoVos.add(formInfoVo);
+
+        }
+        //如果是多实例的
+        if (userTaskConfig.getCountersignConfig().getMultipleInstancesType() != WorkflowMultiInstanceType.NONE.getCode()) {
+            vo.setIsAddOrSubSign(userTaskConfig.getCountersignConfig().getAddOrRemove());
+        }
+        vo.setFormInfos(formInfoVos);
+        vo.setSchemaInfo(BeanUtil.toBean(workflowSchema, WorkflowSchemaInfoVo.class));
+
+        vo.setOpinionConfig(userTaskConfig.getOpinionConfig());
+
+        //如果是多实例的
+        if (userTaskConfig.getCountersignConfig().getMultipleInstancesType() != WorkflowMultiInstanceType.NONE.getCode()) {
+            vo.setIsAddOrSubSign(userTaskConfig.getCountersignConfig().getAddOrRemove());
+        }
+
+        if (userTaskConfig.getOpinionConfig().getEnabled()) {
+            MPJLambdaWrapper<WorkflowApproveRecord> workflowApproveRecordMPJLambdaWrapper = MPJWrappers.<WorkflowApproveRecord>lambdaJoin()
+                    .disableSubLogicDel()
+                    .eq(WorkflowApproveRecord::getProcessId, task.getProcessInstanceId())
+                    .select(WorkflowApproveRecord::getId)
+                    .select(WorkflowApproveRecord.class, x -> VoToColumnUtil.fieldsToColumns(WorkflowApproveRecord.class).contains(x.getProperty()))
+                    .selectAs(User::getName, WorkflowApproveRecord::getApproveUserName)
+                    .leftJoin(User.class, User::getId, WorkflowApproveRecord::getApproveUserId)
+                    .selectAs(Stamp::getFileUrl, WorkflowApproveRecord::getApproveStampUrl)
+                    .leftJoin(Stamp.class, Stamp::getId, WorkflowApproveRecord::getApproveStamp);
+
+            List<WorkflowApproveRecord> approveRecords = approveRecordService.selectJoinList(WorkflowApproveRecord.class, workflowApproveRecordMPJLambdaWrapper);
+
+            //取时间最大值 不好取  目前还是全部查出来 然后根据时间 倒序 取第一条数据
+            if (userTaskConfig.getOpinionConfig().getShowType() == 1 && approveRecords.size() > 0) {
+                WorkflowApproveRecord approveRecord = approveRecords.stream().sorted(Comparator.comparing(WorkflowApproveRecord::getApproveTime).reversed()).collect(Collectors.toList()).get(0);
+                List<WorkflowApproveRecord> onlyOne = new ArrayList<>();
+                onlyOne.add(approveRecord);
+                vo.setTaskApproveOpinions(onlyOne);
+            } else {
+                vo.setTaskApproveOpinions(approveRecords);
+            }
+        }
+        return vo;
+    }
+
+    @Override
+    public ProcessInfoVo getProcessInfo(String processId) {
+        ProcessInfoVo vo = new ProcessInfoVo();
+
+        HistoricVariableInstance historicVariableInstance = historyService.createHistoricVariableInstanceQuery().processInstanceId(processId).variableName(WorkflowConstant.PROCESS_SCHEMA_ID_KEY).singleResult();
+
+        //排除xml 查出数据
+        WorkflowSchema workflowSchema = workflowSchemaMapper.selectOne(Wrappers.lambdaQuery(WorkflowSchema.class).eq(WorkflowSchema::getId, historicVariableInstance.getValue()));
+//        WorkflowSchema workflowSchema = redisUtil.get(WorkflowConstant.SCHEMA_CACHE_PREFIX + extra.getSchemaId(), WorkflowSchema.class);
+
+        //获取到整个流程模板的配置
+        WorkflowSchemaConfig workflowSchemaConfig = JSONUtil.toBean(workflowSchema.getJsonContent(), WorkflowSchemaConfig.class);
+
+
+        List<ProcessRecordListVo> recordListVos = getProcessRecordListVos(processId, 0);
+        vo.setTaskRecords(recordListVos);
+
+        List<Object> allFormConfigs = workflowSchemaConfig.getChildNodeConfig().stream().filter(x -> x.containsKey("formConfigs")).map(x -> x.get("formConfigs")).collect(Collectors.toList());
+        List<FormConfig> formConfigs = new ArrayList<>();
+
+
+        for (Object allFormConfig : allFormConfigs) {
+            List<FormConfig> thisNodeFormConfigs = Convert.toList(FormConfig.class, allFormConfig);
+
+            for (FormConfig thisNodeFormConfig : thisNodeFormConfigs) {
+                if (formConfigs.stream().noneMatch(x -> x.getKey().equals(thisNodeFormConfig.getKey()))) {
+
+                    formConfigs.add(thisNodeFormConfig);
+
+                }
+            }
+        }
+
+
+        String[] allFormKey = formConfigs.stream().map(FormConfig::getKey).toArray(String[]::new);
+
+        List<Long> formIds = formConfigs.stream().map(FormConfig::getFormId).collect(Collectors.toList());
+        List<FormTemplate> formTemplates = formTemplateMapper.selectList(Wrappers.lambdaQuery(FormTemplate.class).in(formIds.size() > 0, FormTemplate::getId, formIds));
+
+
+        List<HistoricVariableInstance> list = historyService.createHistoricVariableInstanceQuery().processInstanceId(processId).variableNameIn(allFormKey).list();
+//        Map<String, Object> allFormData = taskService.getVariables(taskId, allVarKey);
+
+        List<RelationFormInfoVo> formInfoVos = new ArrayList<>(allFormKey.length);
+        for (FormConfig formConfig : formConfigs) {
+
+            RelationFormInfoVo formInfoVo = new RelationFormInfoVo();
+            formInfoVo.setFormType(formConfig.getFormType());
+            formInfoVo.setFormConfig(formConfig);
+
+            if (formConfig.getFormType() == FormTemplateType.CUSTOM.getCode() || formConfig.getFormType() == FormTemplateType.SYSTEM.getCode()) {
+                Optional<FormTemplate> templateOp = formTemplates.stream().filter(f -> Objects.equals(f.getId(), formConfig.getFormId())).findFirst();
+                templateOp.ifPresent(t -> formInfoVo.setFormJson(t.getFormJson()));
+
+                Optional<HistoricVariableInstance> thisFormData = list.stream().filter(x -> x.getName().equals(formConfig.getKey())).findFirst();
+
+                thisFormData.ifPresent(data -> {
+                    Map<String, Object> formData = Convert.toMap(String.class, Object.class, data.getValue());
+                    formInfoVo.setFormData(formData);
+                });
+
+            }
+
+            formInfoVos.add(formInfoVo);
+
+        }
+
+        vo.setFormInfos(formInfoVos);
+        vo.setSchemaInfo(BeanUtil.toBean(workflowSchema, WorkflowSchemaInfoVo.class));
+        vo.setWorkflowChat(workflowSchema.getWorkflowChat());
+
+        return vo;
+    }
+
+    @Override
+    public TaskInfoVo getCirculatedTaskInfo(String taskId) {
+        TaskInfoVo vo = new TaskInfoVo();
+
+        HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery().taskId(taskId).singleResult();
+        WorkflowExtra extra = extraService.getOne(Wrappers.lambdaQuery(WorkflowExtra.class).eq(WorkflowExtra::getTaskId, taskId).select(WorkflowExtra::getSchemaId));
+        WorkflowSchema workflowSchema = workflowSchemaMapper.selectOne(Wrappers.lambdaQuery(WorkflowSchema.class).eq(WorkflowSchema::getId, extra.getSchemaId()));
+
+//        WorkflowSchema workflowSchema = redisUtil.get(WorkflowConstant.SCHEMA_CACHE_PREFIX + extra.getSchemaId(), WorkflowSchema.class);
+
+        //获取到整个流程模板的配置
+        WorkflowSchemaConfig workflowSchemaConfig = JSONUtil.toBean(workflowSchema.getJsonContent(), WorkflowSchemaConfig.class);
+
+        Optional<Map<String, Object>> userNodeConfigOp = workflowSchemaConfig.getChildNodeConfig().stream().filter(c -> c.containsValue(historicTaskInstance.getTaskDefinitionKey())).findFirst();
+
+        if (!userNodeConfigOp.isPresent()) {
+            throw new MyException("当前任务没有开始节点");
+        }
+        List<ProcessRecordListVo> recordListVos = getProcessRecordListVos(historicTaskInstance.getProcessInstanceId(), 0);
+        vo.setTaskRecords(recordListVos);
+
+        //查询任务关联任务
+        vo.setRelationTaskInfo(getRelationTaskVos(historicTaskInstance.getId()));
+
+        //将map 转为 java类
+        UserTaskConfig userTaskConfig = Convert.convert(UserTaskConfig.class, userNodeConfigOp.get());
+
+        List<Long> formIds = userTaskConfig.getFormConfigs().stream().map(FormConfig::getFormId).collect(Collectors.toList());
+        String[] allVarKey = userTaskConfig.getFormConfigs().stream().map(FormConfig::getKey).toArray(String[]::new);
+        List<FormTemplate> formTemplates = formTemplateMapper.selectList(Wrappers.lambdaQuery(FormTemplate.class).in(formIds.size() > 0, FormTemplate::getId, formIds));
+
+        List<HistoricVariableInstance> list = historyService.createHistoricVariableInstanceQuery().variableNameIn(allVarKey).list();
+
+        List<RelationFormInfoVo> formInfoVos = new ArrayList<>(userTaskConfig.getFormConfigs().size());
+        for (FormConfig formConfig : userTaskConfig.getFormConfigs()) {
+
+            RelationFormInfoVo formInfoVo = new RelationFormInfoVo();
+            formInfoVo.setFormType(formConfig.getFormType());
+            formInfoVo.setFormConfig(formConfig);
+
+            //TODO 系统表单 和 自定义表单 走同一套流程  都是使用json  以后看能否有更好的解决方案 解决用户手动修改系统表单代码
+            if (formConfig.getFormType() == FormTemplateType.CUSTOM.getCode() || formConfig.getFormType() == FormTemplateType.SYSTEM.getCode()) {
+                Optional<FormTemplate> templateOp = formTemplates.stream().filter(f -> Objects.equals(f.getId(), formConfig.getFormId())).findFirst();
+                templateOp.ifPresent(t -> formInfoVo.setFormJson(t.getFormJson()));
+
+                Optional<HistoricVariableInstance> thisFormData = list.stream().filter(x -> x.getName().equals(formConfig.getKey())).findFirst();
+
+                thisFormData.ifPresent(data -> {
+                    Map<String, Object> formData = Convert.toMap(String.class, Object.class, data.getValue());
+                    formInfoVo.setFormData(formData);
+                });
+
+            }
+
+            formInfoVos.add(formInfoVo);
+
+        }
+        vo.setFormInfos(formInfoVos);
+        vo.setSchemaInfo(BeanUtil.toBean(workflowSchema, WorkflowSchemaInfoVo.class));
+
+        LambdaQueryWrapper<WorkflowCirculated> queryWrapper = Wrappers.lambdaQuery(WorkflowCirculated.class)
+                .eq(WorkflowCirculated::getTaskId, taskId)
+                .eq(WorkflowCirculated::getCirculatedUserId, StpUtil.getLoginIdAsLong())
+                .select(WorkflowCirculated::getId);
+
+        WorkflowCirculated thisCirculated = circulatedService.getOne(queryWrapper);
+        thisCirculated.setIsRead(YesOrNoEnum.YES.getCode());
+        circulatedService.updateById(thisCirculated);
+
+        return vo;
+    }
+
+    /**
+     * 根据任务id 查询关联任务信息
+     *
+     * @param processId
+     * @return
+     */
+    private List<TaskInfoRelationTaskVo> getRelationTaskVos(String processId) {
+        List<TaskInfoRelationTaskVo> relationTaskVos = new ArrayList<>();
+        List<HistoricVariableInstance> list = historyService.createHistoricVariableInstanceQuery().processInstanceId(processId).variableName(WorkflowConstant.RELATION_TASK_KEY).list();
+
+        if (list != null && list.size() > 0) {
+            List<Object> allRelationTaskInfo = list.stream().map(HistoricVariableInstance::getValue).collect(Collectors.toList());
+            List<LaunchRelationTaskDto> launchRelationTaskDtos = Convert.toList(LaunchRelationTaskDto.class, allRelationTaskInfo);
+
+            List<String> allTaskId = launchRelationTaskDtos.stream().map(LaunchRelationTaskDto::getTaskId).collect(Collectors.toList());
+
+            List<WorkflowExtra> allRelationTask = extraService.list(Wrappers.lambdaQuery(WorkflowExtra.class).in(WorkflowExtra::getTaskId, allTaskId));
+
+            for (WorkflowExtra extra : allRelationTask) {
+                TaskInfoRelationTaskVo relationTaskVo = new TaskInfoRelationTaskVo();
+                relationTaskVo.setTaskId(extra.getTaskId());
+                relationTaskVo.setTaskName(extra.getTaskName());
+                relationTaskVos.add(relationTaskVo);
+            }
+        }
+        return relationTaskVos;
+    }
+
+    @Override
+    public FinishedTaskVo getFinishedTask(String processInstanceId) {
+        FinishedTaskVo vo = new FinishedTaskVo();
+        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
+        if (historicProcessInstance == null) {
+            throw new MyException("流程id不存在!");
+        }
+        List<HistoricActivityInstance> activityInstanceList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).list();
+
+        BpmnModelInstance bpmnModelInstance = repositoryService.getBpmnModelInstance(activityInstanceList.get(0).getProcessDefinitionId());
+
+        List<String> finishedActivity = activityInstanceList.stream().filter(ins -> !ins.isCanceled()).map(ins -> {
+            if (ins.getActivityId().contains(WorkflowConstant.MULTI_INSTANCE_STRING)) {
+                return StrUtil.replace(ins.getActivityId(), WorkflowConstant.MULTI_INSTANCE_STRING, StringPool.EMPTY);
+            } else {
+                return ins.getActivityId();
+            }
+        }).collect(Collectors.toList());
+
+        List<String> outgoingList = new ArrayList<>();
+        for (HistoricActivityInstance historicActivityInstance : activityInstanceList) {//先保存所有已走过节点的outgoing数据
+            ModelElementInstance modelElementById = bpmnModelInstance.getModelElementById(historicActivityInstance.getActivityId());
+
+            //如果包含了多实例的关键字
+            if (historicActivityInstance.getActivityId().contains(WorkflowConstant.MULTI_INSTANCE_STRING)) {
+                String replace = StrUtil.replace(historicActivityInstance.getActivityId(), WorkflowConstant.MULTI_INSTANCE_STRING, StringPool.EMPTY);
+                modelElementById = bpmnModelInstance.getModelElementById(replace);
+            }
+            Collection<SequenceFlow> outgoing = ((FlowNodeImpl) modelElementById).getOutgoing();
+            if (outgoing != null && outgoing.size() > 0) {
+                for (SequenceFlow sequenceFlow : outgoing) {
+                    outgoingList.add(sequenceFlow.getId());
+                }
+            }
+        }
+
+        for (HistoricActivityInstance historicActivityInstance : activityInstanceList) {
+            ModelElementInstance modelElementById = bpmnModelInstance.getModelElementById(historicActivityInstance.getActivityId());
+
+            //如果包含了多实例的关键字
+            if (historicActivityInstance.getActivityId().contains(WorkflowConstant.MULTI_INSTANCE_STRING)) {
+                String replace = StrUtil.replace(historicActivityInstance.getActivityId(), WorkflowConstant.MULTI_INSTANCE_STRING, StringPool.EMPTY);
+                modelElementById = bpmnModelInstance.getModelElementById(replace);
+            }
+            Collection<SequenceFlow> incoming = ((FlowNodeImpl) modelElementById).getIncoming();
+
+            if (incoming != null && incoming.size() > 0) {
+                if (incoming.size() > 1) {
+                    //查询已经走过的节点的outgoing数据
+                    if (CollectionUtil.isNotEmpty(outgoingList)) {
+                        for (SequenceFlow sequenceFlow : incoming) {
+                            if (outgoingList.contains(sequenceFlow.getId())) {
+                                finishedActivity.add(sequenceFlow.getId());
+                            }
+                        }
+                    }
+                } else {
+                    for (SequenceFlow sequenceFlow : incoming) {
+                        finishedActivity.add(sequenceFlow.getId());
+                    }
+                }
+            }
+        }
+        vo.setFinishedNodes(finishedActivity);
+        //如果已经流程结束  就代表没有当前节点
+        if (historicProcessInstance.getEndTime() != null) {
+            return vo;
+        }
+        List<Task> list = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
+        List<String> currentTask = list.stream().map(Task::getTaskDefinitionKey).distinct().collect(Collectors.toList());
+        vo.setCurrentNodes(currentTask);
+
+        return vo;
+    }
+
+    @Override
+    public FormFinishedTaskVo getFormFinishedTask(FormFinishedTaskDto dto) {
+
+        FormFinishedTaskVo vo = new FormFinishedTaskVo();
+        WorkflowSchema workflowSchema = workflowSchemaMapper.selectOne(Wrappers.lambdaQuery(WorkflowSchema.class).eq(WorkflowSchema::getFormId, dto.getFormId()));
+
+        vo.setXmlContent(workflowSchema.getXmlContent());
+
+        WorkflowFormRelation formRelation = formRelationService.getOne(Wrappers.lambdaQuery(WorkflowFormRelation.class).eq(WorkflowFormRelation::getFormId, dto.getFormId()).eq(WorkflowFormRelation::getFormKeyValue, dto.getKeyValue()));
+
+        //如果包含 表单数据 主键值  需要返回 所有已经完成的流程节点内容
+        if (StrUtil.isNotBlank(dto.getKeyValue())) {
+            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(formRelation.getProcessId()).singleResult();
+            if (historicProcessInstance == null) {
+                throw new MyException("流程id不存在!");
+            }
+            List<HistoricActivityInstance> activityInstanceList = historyService.createHistoricActivityInstanceQuery().processInstanceId(formRelation.getProcessId()).list();
+
+            BpmnModelInstance bpmnModelInstance = repositoryService.getBpmnModelInstance(activityInstanceList.get(0).getProcessDefinitionId());
+
+            List<String> finishedActivity = activityInstanceList.stream().filter(ins -> !ins.isCanceled()).map(ins -> {
+                if (ins.getActivityId().contains(WorkflowConstant.MULTI_INSTANCE_STRING)) {
+                    return StrUtil.replace(ins.getActivityId(), WorkflowConstant.MULTI_INSTANCE_STRING, StringPool.EMPTY);
+                } else {
+                    return ins.getActivityId();
+                }
+            }).collect(Collectors.toList());
+
+            for (HistoricActivityInstance historicActivityInstance : activityInstanceList) {
+                ModelElementInstance modelElementById = bpmnModelInstance.getModelElementById(historicActivityInstance.getActivityId());
+
+                //如果包含了多实例的关键字
+                if (historicActivityInstance.getActivityId().contains(WorkflowConstant.MULTI_INSTANCE_STRING)) {
+                    String replace = StrUtil.replace(historicActivityInstance.getActivityId(), WorkflowConstant.MULTI_INSTANCE_STRING, StringPool.EMPTY);
+                    modelElementById = bpmnModelInstance.getModelElementById(replace);
+                }
+                Collection<SequenceFlow> incoming = ((FlowNodeImpl) modelElementById).getIncoming();
+                if (incoming != null && incoming.size() > 0) {
+                    for (SequenceFlow sequenceFlow : incoming) {
+                        finishedActivity.add(sequenceFlow.getId());
+                    }
+                }
+            }
+            vo.setFinishedNodes(finishedActivity);
+            //如果已经流程结束  就代表没有当前节点
+            if (historicProcessInstance.getEndTime() != null) {
+                return vo;
+            }
+            List<Task> list = taskService.createTaskQuery().processInstanceId(formRelation.getProcessId()).list();
+            List<String> currentTask = list.stream().map(Task::getTaskDefinitionKey).distinct().collect(Collectors.toList());
+            vo.setCurrentNodes(currentTask);
+        }
+
+        return vo;
+    }
+
+    @Override
+    public List<ProcessRecordListVo> getProcessRecord(String processInstanceId) {
+        return getProcessRecordListVos(processInstanceId, 0);
+    }
+
+    @Override
+    public PageOutput<CirculatedTaskPageVo> getCirculatedTaskPage(CirculatedTaskPageDto dto) {
+
+        if (ObjectUtil.isNotNull(dto.getStartTime()) && ObjectUtil.isNotNull(dto.getEndTime())) {
+            dto.setStartTime(WorkFlowUtil.getStartOfDay(dto.getStartTime()));
+            dto.setEndTime(WorkFlowUtil.getEndOfDay(dto.getEndTime()));
+        }
+
+        //因为多表关联 会有多个表都使用了id字段,  所以必须专门指定主表的Id
+        IPage<CirculatedTaskPageVo> page = circulatedService.selectJoinListPage(ConventPage.getPage(dto), CirculatedTaskPageVo.class,
+                MPJWrappers.<WorkflowCirculated>lambdaJoin()
+                        .orderByDesc(WorkflowCirculated::getId)
+                        .like(StrUtil.isNotBlank(dto.getTaskName()), WorkflowCirculated::getTaskName, dto.getTaskName())
+                        .like(StrUtil.isNotBlank(dto.getName()), WorkflowSchema::getName, dto.getName())
+                        .like(StrUtil.isNotBlank(dto.getKeyword()), WorkflowSchema::getName, dto.getKeyword())
+                        .eq(StrUtil.isNotBlank(dto.getOriginator()), User::getId, dto.getOriginator())
+                        .eq(StrUtil.isNotBlank(dto.getSerialNumber()), WorkflowCirculated::getSerialNumber, dto.getSerialNumber())
+                        .between(ObjectUtil.isNotNull(dto.getStartTime()) && ObjectUtil.isNotNull(dto.getEndTime()), WorkflowCirculated::getCreateTime, dto.getStartTime(), dto.getEndTime())
+                        .eq(WorkflowCirculated::getCirculatedUserId, StpUtil.getLoginIdAsLong())
+                        .select(WorkflowCirculated::getId)
+                        .select(WorkflowCirculated.class, x -> VoToColumnUtil.fieldsToColumns(CirculatedTaskPageVo.class).contains(x.getProperty()))
+                        .selectAs(WorkflowCirculated::getTaskName, CirculatedTaskPageVo::getCurrentTaskName)
+                        .selectAs(WorkflowSchema::getName, CirculatedTaskPageVo::getSchemaName)
+                        .selectAs(User::getName, CirculatedTaskPageVo::getOriginator)
+                        .leftJoin(User.class, User::getId, WorkflowCirculated::getStartUserId)
+                        .leftJoin(WorkflowSchema.class, WorkflowSchema::getId, WorkflowCirculated::getSchemaId));
+
+        String[] taskIds = page.getRecords().stream().map(CirculatedTaskPageVo::getTaskId).toArray(String[]::new);
+        List<Task> list = taskService.createTaskQuery().taskIdIn(taskIds).list();
+        for (CirculatedTaskPageVo record : page.getRecords()) {
+            Optional<Task> thisTask = list.stream().filter(x -> x.getId().equals(record.getTaskId())).findFirst();
+            if (thisTask.isPresent()) {
+                if (thisTask.get().isSuspended()) {
+                    record.setStatus(2);
+                } else {
+                    record.setStatus(0);
+                }
+            } else {
+                record.setStatus(1);
+            }
+
+        }
+
+        return ConventPage.getPageOutput(page);
+    }
+
+    @Override
+    public PageOutput<FinishedTaskPageVo> getFinishedTaskPage(FinishedTaskPageDto dto) {
+
+//        List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery()
+//                .taskVariableValueLike(WorkflowConstant.TASK_ASSIGNEE_VAR_KEY, StringPool.PERCENT + StpUtil.getLoginIdAsLong() + StringPool.PERCENT)
+//                .list();
+//        List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
+//                .processInstanceId(dto.getProcessId())
+//                .activityType(WorkflowConstant.BPMN_USER_TASK_TYPE_NAME)
+//                .finished()
+//                .orderByHistoricActivityInstanceEndTime()
+//                .asc()
+//                .list();
+//
+
+        if (ObjectUtil.isNotNull(dto.getStartTime()) && ObjectUtil.isNotNull(dto.getEndTime())) {
+            dto.setStartTime(WorkFlowUtil.getStartOfDay(dto.getStartTime()));
+            dto.setEndTime(WorkFlowUtil.getEndOfDay(dto.getEndTime()));
+        }
+
+        //因为多表关联 会有多个表都使用了id字段,  所以必须专门指定主表的Id
+        IPage<FinishedTaskPageVo> page = approveRecordService.selectJoinListPage(ConventPage.getPage(dto), FinishedTaskPageVo.class,
+                MPJWrappers.<WorkflowApproveRecord>lambdaJoin()
+                        .disableSubLogicDel()
+                        .distinct()
+                        .orderByDesc(WorkflowApproveRecord::getId)
+                        .like(StrUtil.isNotBlank(dto.getTaskName()), WorkflowCirculated::getTaskName, dto.getTaskName())
+                        .like(StrUtil.isNotBlank(dto.getName()), WorkflowSchema::getName, dto.getName())
+                        .like(StrUtil.isNotBlank(dto.getKeyword()), WorkflowSchema::getName, dto.getKeyword())
+                        .eq(StrUtil.isNotBlank(dto.getOriginator()), WorkflowExtra::getStartUserId, dto.getOriginator())
+                        .eq(StrUtil.isNotBlank(dto.getSerialNumber()), WorkflowCirculated::getSerialNumber, dto.getSerialNumber())
+                        .between(ObjectUtil.isNotNull(dto.getStartTime()) && ObjectUtil.isNotNull(dto.getEndTime()), WorkflowExtra::getLaunchTime, dto.getStartTime(), dto.getEndTime())
+                        .eq(WorkflowApproveRecord::getApproveUserId, StpUtil.getLoginIdAsLong())
+                        .select(WorkflowApproveRecord::getId)
+                        .select(WorkflowApproveRecord.class, x -> VoToColumnUtil.fieldsToColumns(FinishedTaskPageVo.class).contains(x.getProperty()))
+                        .selectAs(WorkflowSchema::getName, FinishedTaskPageVo::getSchemaName)
+                        .selectAs(WorkflowExtra::getCurrentProgress, FinishedTaskPageVo::getCurrentProgress)
+                        .selectAs(WorkflowExtra::getTaskName, FinishedTaskPageVo::getCurrentTaskName)
+                        .selectAs(WorkflowExtra::getLaunchTime, FinishedTaskPageVo::getCreateTime)
+                        .selectAs(WorkflowExtra::getProcessName, FinishedTaskPageVo::getProcessName)
+                        .selectAs(User::getName, FinishedTaskPageVo::getOriginator)
+                        .leftJoin(User.class, User::getId, WorkflowApproveRecord::getStartUserId)
+                        .leftJoin(WorkflowExtra.class, WorkflowExtra::getTaskId, WorkflowApproveRecord::getTaskId)
+                        .leftJoin(WorkflowSchema.class, WorkflowSchema::getId, WorkflowApproveRecord::getSchemaId));
+
+        return ConventPage.getPageOutput(page);
+
+    }
+
+
+    @Override
+    public PageOutput<MyProcessPageVo> getMyProcessPage(MyProcessPageDto dto) {
+        User user = StpUtil.getTokenSession().get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
+
+        HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery()
+                .variableValueEquals(WorkflowConstant.PROCESS_START_USER_ID_KEY, StpUtil.getLoginIdAsLong())
+                .variableValueEquals(WorkflowConstant.PROCESS_ISRECYCLE_FLAG_KEY, WorkflowIsRecycleType.NO.getCode());
+
+        if (StrUtil.isNotBlank(dto.getSerialNumber()) && StrUtil.isNumeric(dto.getSerialNumber())) {//数字类型
+            historicProcessInstanceQuery.variableValueEquals(WorkflowConstant.PROCESS_SERIAL_NUMBER_KEY, Long.valueOf(dto.getSerialNumber()));
+        }
+        if (!ObjectUtil.isNull(dto.getStartTime())) {
+            historicProcessInstanceQuery.startedAfter(WorkFlowUtil.getStartOfDay(dto.getStartTime()));
+        }
+        if (!ObjectUtil.isNull(dto.getEndTime())) {
+            historicProcessInstanceQuery.startedBefore(WorkFlowUtil.getEndOfDay(dto.getEndTime()));
+        }
+        if (StrUtil.isNotBlank(dto.getName())) {
+            historicProcessInstanceQuery.variableValueLike(WorkflowConstant.PROCESS_SCHEMA_NAME_KEY, StringPool.PERCENT + dto.getName() + StringPool.PERCENT);
+        }
+        if (StrUtil.isNotBlank(dto.getSchemaId())) {
+            historicProcessInstanceQuery.variableValueEquals(WorkflowConstant.PROCESS_SCHEMA_ID_KEY, Convert.toLong(dto.getSchemaId()));
+        }
+        if (StrUtil.isNotBlank(dto.getKeyword())) {
+            historicProcessInstanceQuery.variableValueLike(WorkflowConstant.PROCESS_SCHEMA_NAME_KEY, StringPool.PERCENT + dto.getKeyword() + StringPool.PERCENT);
+        }
+        if (StrUtil.isNotBlank(dto.getOriginator())) {
+            historicProcessInstanceQuery.or()
+                    .variableValueEquals(WorkflowConstant.PROCESS_START_USER_NAME_KEY, dto.getOriginator())
+                    .variableValueEquals(WorkflowConstant.PROCESS_START_USER_ID_KEY, dto.getOriginator())
+                    .endOr();
+        }
+
+        if (!ObjectUtil.isNull(dto.getType()) && dto.getType() == 1) {
+            historicProcessInstanceQuery.finished();
+        }
+        if (!ObjectUtil.isNull(dto.getType()) && dto.getType() == 2) {
+            historicProcessInstanceQuery.unfinished();
+        }
+
+
+        long count = historicProcessInstanceQuery.count();
+        List<HistoricProcessInstance> historicProcessInstances = historicProcessInstanceQuery.orderByProcessInstanceStartTime().desc().listPage(Convert.toInt((dto.getLimit() - 1) * dto.getSize()), dto.getSize());
+
+        //获取到所有流程id
+        List<String> processIds = historicProcessInstances.stream().map(HistoricProcessInstance::getId).collect(Collectors.toList());
+
+
+        List<MyProcessPageVo> result = new ArrayList<>(historicProcessInstances.size());
+        if (processIds.size() > 0) {
+
+            List<WorkflowExtra> workflowExtras = workflowExtraMapper.selectList(Wrappers.lambdaQuery(WorkflowExtra.class).in(WorkflowExtra::getProcessId, processIds));
+
+            for (HistoricProcessInstance historicProcessInstance : historicProcessInstances) {
+
+                //找到当前流程的 任务开始时间 最大值  为当前审批节点
+                workflowExtras.stream()
+                        .filter(e -> e.getProcessId().equals(historicProcessInstance.getId()))
+                        .max(Comparator.comparing(WorkflowExtra::getStartTime))
+                        .ifPresent(e -> {
+                            MyProcessPageVo vo = new MyProcessPageVo();
+                            vo.setId(e.getId());
+                            vo.setSerialNumber(e.getSerialNumber());
+                            vo.setSchemaName(e.getSchemaName());
+                            vo.setOriginator(e.getStartUserName());
+                            vo.setSchemaId(e.getSchemaId());
+
+                            vo.setTaskName(e.getTaskName());
+                            vo.setCurrentTaskName(e.getTaskName());
+                            vo.setTaskId(e.getTaskId());
+                            vo.setCreateTime(e.getStartTime());
+                            vo.setProcessId(e.getProcessId());
+                            vo.setProcessName(e.getProcessName());
+
+                            //如果是已经完成的任务 默认是100进度
+                            if (ObjectUtil.isNotNull(historicProcessInstance.getEndTime())) {
+                                vo.setCurrentProgress(100);
+                                vo.setCurrentTaskName(WorkflowConstant.END_NODE_TYPE_NAME);
+                            } else {
+                                vo.setCurrentProgress(e.getCurrentProgress());
+                            }
+
+                            result.add(vo);
+                        });
+
+
+                MyProcessPageVo vo = new MyProcessPageVo();
+
+            }
+        }
+
+        if (StrUtil.isNotBlank(dto.getSerialNumber()) && !StrUtil.isNumeric(dto.getSerialNumber())) {//非数字类型置空
+            result.clear();
+        }
+        PageOutput<MyProcessPageVo> output = new PageOutput<>();
+        output.setCurrentPage(dto.getLimit());
+        output.setPageSize(dto.getSize());
+        output.setTotal(Convert.toInt(count));
+        output.setList(result);
+        return output;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean moveRecycle(MoveRecycleDto dto) {
+
+
+//        User user = StpUtil.getTokenSession().get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
+//
+//        Object startUserId = runtimeService.getVariable(processInstanceId, WorkflowConstant.PROCESS_START_USER_ID_KEY);
+//
+//        //判断是否为发起人
+//        if (!ObjectUtil.equals(startUserId, user.getId())) {
+//            throw new MyException("您不是发起人 无法移入回收站!");
+//        }
+
+        //此代码为适配老版本功能  将移入回收站的流程挂起
+        {
+            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(dto.getProcessId()).singleResult();
+
+            if (processInstance != null) {
+                VariableMap variableMap = Variables.createVariables().putValue(WorkflowConstant.PROCESS_ISRECYCLE_FLAG_KEY, WorkflowIsRecycleType.YES.getCode());
+
+                runtimeService.setVariables(dto.getProcessId(), variableMap);
+//                runtimeService.deleteProcessInstance(dto.getProcessId(), "流程移入回收站");
+
+            } else {
+                HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(dto.getProcessId()).singleResult();
+                if (historicProcessInstance.getEndTime() != null) {
+                    throw new MyException("流程已结束不能放入回收站!");
+                } else {
+                    throw new MyException("找不到此流程!");
+                }
+            }
+
+
+        }
+
+        //此代码为直接关闭流程代码
+        {
+//        //获取到当前活动的实例
+//        ActivityInstance activityInstance = runtimeService.getActivityInstance(processInstanceId);
+//
+//        //先停止当前活动示例  然后  关闭流程
+//        runtimeService.createProcessInstanceModification(processInstanceId)
+//                .cancelAllForActivity(activityInstance.getId())
+//                .setAnnotation("【发起人:" + user.getName() + "】 将 【流程:" + processInstanceId + "】 移入回收站 所有流程关闭!" )
+//                .execute();
+        }
+
+        return true;
+    }
+
+    @Override
+    public PageOutput<RecycleProcessPageVo> getRecycleProcessPage(RecycleProcessPageDto dto) {
+
+        if (ObjectUtil.isNotNull(dto.getStartTime()) && ObjectUtil.isNotNull(dto.getEndTime())) {
+            dto.setStartTime(WorkFlowUtil.getStartOfDay(dto.getStartTime()));
+            dto.setEndTime(WorkFlowUtil.getEndOfDay(dto.getEndTime()));
+        }
+
+        User user = StpUtil.getTokenSession().get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
+
+        HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery()
+                .variableValueEquals(WorkflowConstant.PROCESS_START_USER_ID_KEY, user.getId())
+                .variableValueEquals(WorkflowConstant.PROCESS_ISRECYCLE_FLAG_KEY, WorkflowIsRecycleType.YES.getCode());
+
+        if (StrUtil.isNotBlank(dto.getSerialNumber()) && StrUtil.isNumeric(dto.getSerialNumber())) {
+            historicProcessInstanceQuery.variableValueEquals(WorkflowConstant.PROCESS_SERIAL_NUMBER_KEY, Long.valueOf(dto.getSerialNumber()));
+        }
+        if (!ObjectUtil.isNull(dto.getStartTime())) {
+            historicProcessInstanceQuery.startedAfter(dto.getStartTime());
+        }
+        if (!ObjectUtil.isNull(dto.getEndTime())) {
+            historicProcessInstanceQuery.startedBefore(dto.getEndTime());
+        }
+        if (StrUtil.isNotBlank(dto.getName())) {
+            historicProcessInstanceQuery.variableValueEquals(WorkflowConstant.PROCESS_SCHEMA_NAME_KEY, StringPool.PERCENT + dto.getName() + StringPool.PERCENT);
+        }
+        if (StrUtil.isNotBlank(dto.getInitiator())) {
+            historicProcessInstanceQuery.variableValueEquals(WorkflowConstant.PROCESS_START_USER_NAME_KEY, dto.getInitiator());
+        }
+
+        long count = historicProcessInstanceQuery.count();
+        List<HistoricProcessInstance> historicProcessInstances = historicProcessInstanceQuery.listPage(Convert.toInt((dto.getLimit() - 1) * dto.getSize()), dto.getSize());
+
+        //获取到所有流程id
+        List<String> processIds = historicProcessInstances.stream().map(HistoricProcessInstance::getId).collect(Collectors.toList());
+
+
+        List<RecycleProcessPageVo> result = new ArrayList<>(historicProcessInstances.size());
+        if (processIds.size() > 0) {
+
+            List<WorkflowExtra> workflowExtras = workflowExtraMapper.selectList(Wrappers.lambdaQuery(WorkflowExtra.class).in(WorkflowExtra::getProcessId, processIds));
+
+            for (HistoricProcessInstance historicProcessInstance : historicProcessInstances) {
+
+                //找到当前流程的 任务开始时间 最大值  为当前审批节点
+                workflowExtras.stream()
+                        .filter(e -> e.getProcessId().equals(historicProcessInstance.getId()))
+                        .max(Comparator.comparing(WorkflowExtra::getStartTime))
+                        .ifPresent(e -> {
+                            RecycleProcessPageVo vo = new RecycleProcessPageVo();
+                            vo.setSerialNumber(e.getSerialNumber());
+                            vo.setSchemaName(e.getSchemaName());
+                            vo.setOriginator(e.getStartUserName());
+                            vo.setSchemaId(e.getSchemaId());
+                            vo.setCurrentProgress(e.getCurrentProgress());
+                            vo.setTaskName(e.getTaskName());
+                            vo.setProcessId(e.getProcessId());
+                            vo.setCreateTime(e.getLaunchTime());
+                            vo.setCurrentTaskName(e.getTaskName());
+                            vo.setTaskId(e.getTaskId());
+                            vo.setProcessName(e.getProcessName());
+                            result.add(vo);
+                        });
+            }
+        }
+        if (StrUtil.isNotBlank(dto.getSerialNumber()) && !StrUtil.isNumeric(dto.getSerialNumber())) {
+            result.clear();
+        }
+
+        PageOutput<RecycleProcessPageVo> output = new PageOutput<>();
+        output.setCurrentPage(dto.getLimit());
+        output.setPageSize(dto.getSize());
+        output.setTotal(Convert.toInt(count));
+        result.sort((t1, t2) -> t2.getCreateTime().compareTo(t1.getCreateTime()));
+        output.setList(result);
+        return output;
+    }
+
+    @Override
+    public RestartVo restart(RestartDto dto) {
+
+        //排除xml 查出数据
+        WorkflowSchema workflowSchema = workflowSchemaMapper.selectOne(Wrappers.lambdaQuery(WorkflowSchema.class).eq(WorkflowSchema::getId, dto.getSchemaId()).select(x -> !x.getProperty().startsWith(DB_FIELD_XML_PREFIX)));
+
+        //获取到整个流程模板的配置
+        WorkflowSchemaConfig workflowSchemaConfig = JSONUtil.toBean(workflowSchema.getJsonContent(), WorkflowSchemaConfig.class);
+
+        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(dto.getProcessId()).singleResult();
+
+        Optional<Map<String, Object>> startNodeMapOp = workflowSchemaConfig.getChildNodeConfig().stream().filter(x -> x.containsValue(historicProcessInstance.getStartActivityId())).findFirst();
+
+        if (!startNodeMapOp.isPresent()) {
+            throw new MyException("找不到开始节点的配置信息");
+        }
+
+        //将map 转为 java类
+        StartNodeConfig startNodeConfig = Convert.convert(StartNodeConfig.class, startNodeMapOp.get());
+
+        RestartVo vo = new RestartVo();
+        vo.setFormDatas(new HashMap<>());
+
+        String[] startNodeFormKey = startNodeConfig.getFormConfigs().stream().map(c -> WorkflowConstant.PROCESS_FORMDATA_PREFIX_KEY + c.getFormId()).toArray(String[]::new);
+
+        List<HistoricVariableInstance> list = historyService.createHistoricVariableInstanceQuery().processInstanceId(dto.getProcessId()).variableNameIn(startNodeFormKey).list();
+
+        for (HistoricVariableInstance historicVariableInstance : list) {
+            vo.getFormDatas().put(historicVariableInstance.getName(), Convert.toMap(String.class, Object.class, historicVariableInstance.getValue()));
+        }
+
+
+        vo.setSchemaInfo(BeanUtil.toBean(workflowSchema, WorkflowSchemaInfoVo.class));
+        return vo;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean recycleDelete(RecycleDeleteDto dto) {
+
+        for (String processId : dto.getProcessIds()) {
+            runtimeService.deleteProcessInstance(processId, "流程移入回收站");
+        }
+        return true;
+    }
+
+    @Override
+    public List<HistoryTaskVo> getHistoryTask(String schemaId, String processInstanceId) {
+
+        List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId).list();
+        WorkflowSchema workflowSchema = workflowSchemaMapper.selectOne(Wrappers.lambdaQuery(WorkflowSchema.class).eq(WorkflowSchema::getId, schemaId));
+//        WorkflowSchema workflowSchema = redisUtil.get(WorkflowConstant.SCHEMA_CACHE_PREFIX + schemaId, WorkflowSchema.class);
+
+        WorkflowSchemaConfig workflowSchemaConfig = JSONUtil.toBean(workflowSchema.getJsonContent(), WorkflowSchemaConfig.class);
+
+        List<HistoryTaskVo> result = new ArrayList<>();
+
+        for (HistoricTaskInstance task : list) {
+            Optional<Map<String, Object>> taskConfigMapOp = workflowSchemaConfig.getChildNodeConfig()
+                    .stream()
+                    .filter(n -> n.containsValue(task.getTaskDefinitionKey()))
+                    .findFirst();
+
+            taskConfigMapOp.ifPresent(map -> {
+                //将map 转为 java类
+                UserTaskConfig userTaskConfig = Convert.convert(UserTaskConfig.class, map);
+                HistoryTaskVo vo = new HistoryTaskVo();
+                //必须非会签系节点
+                if (userTaskConfig.getCountersignConfig().getMultipleInstancesType() == WorkflowMultiInstanceType.NONE.getCode()) {
+                    vo.setTaskId(task.getId());
+                    vo.setTaskName(task.getName());
+                    result.add(vo);
+                }
+
+            });
+        }
+
+        return result;
+    }
+
+    @Override
+    public boolean withdraw(WithdrawDto dto) {
+
+        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(dto.getProcessId()).singleResult();
+
+        User user = StpUtil.getTokenSession().get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
+
+        if (historicProcessInstance.getEndTime() != null) {
+            throw new MyException("流程已经结束  无法撤回!");
+        }
+        //如果是简单流程 无多实例 无网关等组件 默认可以根据审批时间
+
+        //获取到当前活动的实例
+        ActivityInstance activityInstance = runtimeService.getActivityInstance(dto.getProcessId());
+
+        //获取当前活动的任务信息
+        List<WorkflowExtra> workflowExtras = workflowExtraMapper.selectList(Wrappers.lambdaQuery(WorkflowExtra.class).in(WorkflowExtra::getProcessId, dto.getProcessId()));
+        //找到当前流程的 任务开始时间 最大值  为当前审批节点
+        WorkflowExtra workflowExtra = workflowExtras.stream()
+                .filter(e -> e.getProcessId().equals(dto.getProcessId()))
+                .max(Comparator.comparing(WorkflowExtra::getStartTime)).orElse(new WorkflowExtra());
+        //新增流程发起流程记录
+        WorkflowRecord record = new WorkflowRecord();
+        record.setNodeId(workflowExtra.getTaskId());
+        record.setNodeName(workflowExtra.getTaskName());
+        record.setNodeType(workflowExtra.getTaskName());
+        record.setProcessId(dto.getProcessId());
+        record.setSchemaId(workflowExtra.getSchemaId());
+        record.setNodeMultiType(WorkflowMultiInstanceType.NONE.getCode());
+        record.setRecordTime(LocalDateTime.now());
+        String oldTaskName = workflowExtra.getTaskName();
+        //如果传入的是开始节点的值  默认是关闭流程  重新发起
+        if (StrUtil.equals(dto.getActivityId(), historicProcessInstance.getStartActivityId())) {
+
+            runtimeService.deleteProcessInstance(historicProcessInstance.getId(), "【发起人:" + user.getName() + "】 将 【流程:" + historicProcessInstance.getProcessDefinitionName() + "】 撤回 到  开始节点!");
+//            //先停止当前活动示例  然后  将流程撤回到开始节点
+//            runtimeService.createProcessInstanceModification(dto.getProcessId())
+//                    .cancelActivityInstance(activityInstance.getId())
+//                    .setAnnotation("【发起人:" + user.getName() + "】 将 【流程:" + historicProcessInstance.getProcessDefinitionName() + "】 撤回 到  开始节点!")
+//                    .startBeforeActivity(historicProcessInstance.getStartActivityId())
+//                    .setVariableLocal(WorkflowConstant.TASK_IS_APPOINT_APPROVE,YesOrNoEnum.NO.getCode())
+//                    .execute();
+            record.setMessage("【" + user.getName() + "】 将当前流程从【" + oldTaskName + "】 撤回 到 【开始节点】!");
+        } else {
+            //先停止当前活动示例  然后  将流程撤回到某个节点
+            runtimeService.createProcessInstanceModification(historicProcessInstance.getId())
+                    .cancelActivityInstance(activityInstance.getId())
+                    .setAnnotation("【发起人:" + user.getName() + "】 将 【流程:" + historicProcessInstance.getProcessDefinitionName() + "】 撤回 到 【任务:" + activityInstance.getActivityName() + "】!")
+                    .startBeforeActivity(dto.getActivityId())
+                    .setVariableLocal(WorkflowConstant.TASK_IS_APPOINT_APPROVE, YesOrNoEnum.NO.getCode())
+                    .execute();
+
+            //获取当前活动的任务信息
+            List<WorkflowExtra> workflowExtrasNew = workflowExtraMapper.selectList(Wrappers.lambdaQuery(WorkflowExtra.class).in(WorkflowExtra::getProcessId, dto.getProcessId()));
+            //找到当前流程的 任务开始时间 最大值  为当前审批节点
+            WorkflowExtra workflowExtraNew = workflowExtrasNew.stream()
+                    .filter(e -> e.getProcessId().equals(dto.getProcessId()))
+                    .max(Comparator.comparing(WorkflowExtra::getStartTime)).orElse(new WorkflowExtra());
+            record.setMessage("【" + user.getName() + "】 将当前流程从【" + oldTaskName + "】撤回 到【" + workflowExtraNew.getTaskName() + "】!");
+        }
+        //保存流程撤回信息
+        workflowRecordMapper.insert(record);
+        return true;
+    }
+
+    @Override
+    public boolean saveDraft(SaveDraftDto dto) {
+
+        WorkflowDraft draft = BeanUtil.toBean(dto, WorkflowDraft.class);
+        draft.setFormData(JSONUtil.toJsonStr(dto.getFormData()));
+
+        return workflowDraftService.save(draft);
+    }
+
+    @Override
+    public boolean updateDraft(UpdateDraftDto dto) {
+
+        WorkflowDraft draft = new WorkflowDraft();
+        draft.setId(dto.getId());
+        draft.setFormData(JSONUtil.toJsonStr(dto.getFormData()));
+
+        return workflowDraftService.updateById(draft);
+
+    }
+
+    @Override
+    public PageOutput<DraftPageVo> draftPage(DraftPageDto dto) {
+
+        if (ObjectUtil.isNotNull(dto.getStartTime()) && ObjectUtil.isNotNull(dto.getEndTime())) {
+            dto.setStartTime(WorkFlowUtil.getStartOfDay(dto.getStartTime()));
+            dto.setEndTime(WorkFlowUtil.getEndOfDay(dto.getEndTime()));
+        }
+
+        List<Long> ids = new ArrayList<>();
+        //发起人分割数组
+        if (StrUtil.isNotBlank(dto.getOriginator())) {
+            String allUserIdStr = StrUtil.join(StringPool.COMMA, dto.getOriginator());
+            ids = Arrays.stream(allUserIdStr.split(StringPool.COMMA)).map(Convert::toLong).collect(Collectors.toList());
+        }
+        ids.add(StpUtil.getLoginIdAsLong());
+
+        //因为多表关联 会有多个表都使用了id字段,  所以必须专门指定主表的Id
+        IPage<DraftPageVo> page = workflowDraftService.selectJoinListPage(ConventPage.getPage(dto), DraftPageVo.class,
+                MPJWrappers.<WorkflowDraft>lambdaJoin()
+                        .disableSubLogicDel()
+                        .eq(StrUtil.isNotBlank(dto.getName()), WorkflowSchema::getName, dto.getName())
+                        .in(CollectionUtil.isNotEmpty(ids), WorkflowDraft::getCreateUserId, ids)
+                        .between(ObjectUtil.isNotNull(dto.getStartTime()) && ObjectUtil.isNotNull(dto.getEndTime()), WorkflowDraft::getCreateDate, dto.getStartTime(), dto.getEndTime())
+                        .orderByDesc(WorkflowDraft::getCreateDate)
+                        .select(WorkflowDraft::getId)
+                        .select(WorkflowDraft.class, x -> VoToColumnUtil.fieldsToColumns(DraftPageVo.class).contains(x.getProperty()))
+                        .selectAs(WorkflowSchema::getName, DraftPageVo::getSchemaName)
+                        .selectAs(User::getName, DraftPageVo::getOriginator)
+                        .leftJoin(WorkflowSchema.class, WorkflowSchema::getId, WorkflowDraft::getSchemaId)
+                        .leftJoin(User.class, User::getId, WorkflowDraft::getCreateUserId));
+
+        return ConventPage.getPageOutput(page);
+
+    }
+
+    @Override
+    public boolean deleteDraft(List<Long> ids) {
+        return workflowDraftService.removeBatchByIds(ids);
+    }
+
+    @Override
+    public DraftInfoVo draftData(Long id) {
+        WorkflowDraft draft = workflowDraftService.getById(id);
+        return BeanUtil.toBean(draft, DraftInfoVo.class);
+    }
+
+    @Override
+    public PageOutput<MonitorPageVo> getProcessMonitorPage(MonitorPageDto dto) {
+
+        HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery();
+
+        if (!ObjectUtil.isNull(dto.getStartTime())) {
+            historicProcessInstanceQuery.startedAfter(WorkFlowUtil.getStartOfDay(dto.getStartTime()));
+        }
+        if (!ObjectUtil.isNull(dto.getEndTime())) {
+            historicProcessInstanceQuery.startedBefore(WorkFlowUtil.getEndOfDay(dto.getEndTime()));
+        }
+        if (StrUtil.isNotBlank(dto.getKeyword())) {
+            historicProcessInstanceQuery
+                    .or()
+                    .variableValueLike(WorkflowConstant.PROCESS_SCHEMA_NAME_KEY, StringPool.PERCENT + dto.getKeyword() + StringPool.PERCENT)
+                    .variableValueLike(WorkflowConstant.PROCESS_START_USER_NAME_KEY, StringPool.PERCENT + dto.getKeyword() + StringPool.PERCENT)
+                    .variableValueEquals(WorkflowConstant.PROCESS_SERIAL_NUMBER_KEY, StrUtil.isNumeric(dto.getKeyword()) ? Convert.toLong(dto.getKeyword()) : 0L)
+                    .endOr();
+        }
+        if (dto.getType() == 1) {
+            historicProcessInstanceQuery.finished();
+        }
+        if (dto.getType() == 0) {
+            historicProcessInstanceQuery.unfinished();
+        }
+
+        long count = historicProcessInstanceQuery.count();
+//        List<HistoricProcessInstance> historicProcessInstances = historicProcessInstanceQuery.listPage(Convert.toInt((dto.getLimit() - 1) * dto.getSize()), dto.getSize());
+        List<HistoricProcessInstance> historicProcessInstances = historicProcessInstanceQuery.list();
+
+        //获取到所有流程id
+        List<String> processIds = historicProcessInstances.stream().map(HistoricProcessInstance::getId).collect(Collectors.toList());
+
+
+        List<MonitorPageVo> result = new ArrayList<>(historicProcessInstances.size());
+        if (processIds.size() > 0) {
+
+            List<WorkflowExtra> workflowExtras = workflowExtraMapper.selectList(Wrappers.lambdaQuery(WorkflowExtra.class).in(WorkflowExtra::getProcessId, processIds));
+
+            for (HistoricProcessInstance historicProcessInstance : historicProcessInstances) {
+
+
+                //找到当前流程的 任务开始时间 最大值  为当前审批节点
+                workflowExtras.stream()
+                        .filter(e -> e.getProcessId().equals(historicProcessInstance.getId()))
+                        .max(Comparator.comparing(WorkflowExtra::getStartTime))
+                        .ifPresent(e -> {
+                            MonitorPageVo vo = new MonitorPageVo();
+                            vo.setProcessId(e.getProcessId());
+                            vo.setTaskId(e.getTaskId());
+                            vo.setSerialNumber(e.getSerialNumber());
+                            vo.setSchemaName(e.getSchemaName());
+                            vo.setOriginator(e.getStartUserName());
+                            vo.setSchemaId(e.getSchemaId());
+
+                            //如果是已经完成的任务 默认是100进度
+                            if (ObjectUtil.isNotNull(historicProcessInstance.getEndTime())) {
+                                vo.setCurrentProgress(100);
+                            } else {
+                                vo.setCurrentProgress(e.getCurrentProgress());
+                            }
+                            vo.setCurrentTaskName(e.getTaskName());
+
+                            //如果当前任务是外部流程任务
+                            if (StrUtil.isBlank(e.getTaskId())) {//只有可能是外部流程任务或者脚本任务,但脚本任务会直接完成度100%,所以直接设值为外部流程任务
+                                vo.setCurrentTaskName(WorkflowConstant.CALL_ACTIVITY_TYPE_NAME);
+                            }
+                            vo.setStatus(historicProcessInstance.getState());
+                            vo.setStatusMessage(historicProcessInstance.getState().equals("SUSPENDED") ? "挂起" : "");
+                            vo.setCreateDate(e.getStartTime());
+
+                            result.add(vo);
+                        });
+            }
+        }
+        result.sort((t1, t2) -> t2.getCreateDate().compareTo(t1.getCreateDate()));
+        PageOutput<MonitorPageVo> output = new PageOutput<>();
+        output.setCurrentPage(dto.getLimit());
+        output.setPageSize(dto.getSize());
+        output.setTotal(Convert.toInt(count));
+        output.setList(result);
+        return output;
+    }
+
+    @Override
+    public boolean setAssignee(SetAssigneeDto dto) {
+        Task task = taskService.createTaskQuery().taskId(dto.getTaskId()).singleResult();
+        if (task == null) {
+            throw new MyException("找不到此流程!");
+        }
+        if (task.isSuspended()) {
+            throw new MyException("流程已挂起,无法指定审批人!");
+        }
+
+        Object assigneesObject = taskService.getVariable(dto.getTaskId(), WorkflowConstant.TASK_ASSIGNEE_VAR_KEY);
+
+        List<String> assignees = ListUtil.toList(Convert.toStr(assigneesObject).split(StringPool.COMMA));
+        assignees.addAll(dto.getAssignees());
+        taskService.setVariable(dto.getTaskId(), WorkflowConstant.TASK_ASSIGNEE_VAR_KEY, StrUtil.join(StringPool.COMMA, assignees));
+
+        Long schemaId = Convert.toLong(taskService.getVariable(task.getId(), WorkflowConstant.PROCESS_SCHEMA_ID_KEY));
+        //获取当前用户的信息
+        User user = StpUtil.getTokenSession().get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
+        //新增流程发起流程记录
+        WorkflowRecord record = new WorkflowRecord();
+        record.setNodeId(task.getId());
+        record.setNodeName(task.getName());
+        record.setNodeType(WorkflowConstant.USER_TASK_TYPE_NAME);
+        record.setProcessId(task.getProcessInstanceId());
+        record.setSchemaId(schemaId);
+        record.setNodeMultiType(WorkflowMultiInstanceType.NONE.getCode());
+        record.setRecordTime(LocalDateTime.now());
+        //[操作人名称] 通过[指派审核人] 指派[被指派人名称]作为审核人
+        List<Long> allAssigneesUserIds = dto.getAssignees().stream().mapToLong(t -> Long.parseLong(t.trim())).boxed().collect(Collectors.toList());
+        String allAssigneesUserNames = getAllUserNamesByIds(allAssigneesUserIds);
+        record.setMessage("【" + user.getName() + "】通过【指派审核人】指派【" + allAssigneesUserNames + "】作为审核人");
+
+        workflowRecordMapper.insert(record);
+        return true;
+    }
+
+    @Override
+    public boolean setSuspended(SetSuspendedDto dto) {
+
+        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(dto.getProcessId()).singleResult();
+
+        List<Task> taskList = taskService.createTaskQuery()
+                .processInstanceId(dto.getProcessId())
+                .list();
+        Task task = taskList.stream().filter(x -> x.getProcessInstanceId().equals(dto.getProcessId())).findFirst().orElse(new TaskEntity());
+        //获取当前用户的信息
+        User user = StpUtil.getTokenSession().get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
+        Long schemaId = Convert.toLong(taskService.getVariable(task.getId(), WorkflowConstant.PROCESS_SCHEMA_ID_KEY));
+        //新增流程发起流程记录
+        WorkflowRecord record = new WorkflowRecord();
+        record.setNodeId(task.getId());
+        record.setNodeName(task.getName());
+        record.setNodeType(WorkflowConstant.USER_TASK_TYPE_NAME);
+        record.setProcessId(task.getProcessInstanceId());
+        record.setSchemaId(schemaId);
+        record.setNodeMultiType(WorkflowMultiInstanceType.NONE.getCode());
+        record.setRecordTime(LocalDateTime.now());
+
+        if (processInstance.isSuspended()) {
+            runtimeService.activateProcessInstanceById(dto.getProcessId());
+            //[操作人名称] 将流程恢复
+            record.setMessage("【" + user.getName() + "】将流程恢复");
+            workflowRecordMapper.insert(record);
+        } else {
+            runtimeService.suspendProcessInstanceById(dto.getProcessId());
+            //[操作人名称] 将流程挂起
+            record.setMessage("【" + user.getName() + "】将流程挂起");
+            workflowRecordMapper.insert(record);
+        }
+
+        return true;
+    }
+
+    @Override
+    public List<GetAssigneeVo> getAssignee(GetAssigneeDto dto) {
+        //排除xml 查出数据
+        WorkflowSchema workflowSchema = workflowSchemaMapper.selectOne(Wrappers.lambdaQuery(WorkflowSchema.class).eq(WorkflowSchema::getId, dto.getSchemaId()).select(x -> !x.getProperty().startsWith(DB_FIELD_XML_PREFIX)));
+
+        if (workflowSchema == null) {
+            throw new MyException("找不到此流程模板!");
+        }
+
+        //如果当前模板被禁用 无法操作流程
+        if (workflowSchema.getEnabledMark() == EnabledMark.DISABLED.getCode()) {
+            throw new MyException("流程被禁用!");
+        }
+
+        //获取到整个流程模板的配置
+        WorkflowSchemaConfig workflowSchemaConfig = JSONUtil.toBean(workflowSchema.getJsonContent(), WorkflowSchemaConfig.class);
+
+        Task task = taskService.createTaskQuery().taskId(dto.getTaskId()).singleResult();
+
+        Optional<Map<String, Object>> userTaskConfigOp = workflowSchemaConfig.getChildNodeConfig().stream().filter(c -> c.containsValue(task.getTaskDefinitionKey())).findFirst();
+
+        if (!userTaskConfigOp.isPresent()) {
+            throw new MyException("找不到当前节点配置!");
+        }
+        //    将map 转为 java类
+        UserTaskConfig userTaskConfig = Convert.convert(UserTaskConfig.class, userTaskConfigOp.get());
+
+        List<User> users = redisUtil.get(GlobalConstant.USER_CACHE_KEY, new TypeReference<List<User>>() {
+        });
+        List<GetAssigneeVo> result = new ArrayList<>();
+
+        //如果是单实例任务
+        if (userTaskConfig.getCountersignConfig().getMultipleInstancesType() == WorkflowMultiInstanceType.NONE.getCode()) {
+            Object assigneeObj = taskService.getVariable(dto.getTaskId(), WorkflowConstant.TASK_ASSIGNEE_VAR_KEY);
+            List<String> taskAssignee = StrUtil.split(Convert.toStr(assigneeObj), StringPool.COMMA);
+
+
+            List<User> assigneeUserInfo = users.stream().filter(u -> taskAssignee.contains(StrUtil.toString(u.getId()))).collect(Collectors.toList());
+
+            for (User user : assigneeUserInfo) {
+                GetAssigneeVo vo = BeanUtil.toBean(user, GetAssigneeVo.class);
+
+                //如果不是当前登录用户 就可以移除
+                vo.setCanRemove(StpUtil.getLoginIdAsLong() != user.getId());
+                result.add(vo);
+            }
+
+        }
+        //如果是多实例任务
+        else {
+
+            Object assigneeObj = runtimeService.getVariable(task.getProcessInstanceId(), WorkflowConstant.TASK_MULTI_ASSIGNEE_VAR_KEY + task.getTaskDefinitionKey());
+            List<Long> taskAssignee = Convert.toList(Long.class, assigneeObj);
+
+            List<User> assigneeUserInfo = users.stream().filter(u -> taskAssignee.contains(u.getId())).collect(Collectors.toList());
+
+            //查询审批记录表,xjr_workflow_approve_record,流程id和节点的key值查询有哪些用户审批过了
+            List<WorkflowApproveRecord> list = approveRecordService.list(Wrappers.lambdaQuery(WorkflowApproveRecord.class)
+                    .eq(WorkflowApproveRecord::getProcessId, task.getProcessInstanceId())
+                    .eq(WorkflowApproveRecord::getTaskDefinitionKey, task.getTaskDefinitionKey())
+            );
+
+            List<Long> approveUserIds = new ArrayList<>();
+            if (list.size() != 0) {
+                //已审批的用户id
+                approveUserIds = list.stream().map(WorkflowApproveRecord::getApproveUserId).collect(Collectors.toList());
+            }
+            for (User user : assigneeUserInfo) {
+                GetAssigneeVo vo = BeanUtil.toBean(user, GetAssigneeVo.class);
+
+                //同步都不能减签
+                if (userTaskConfig.getCountersignConfig().getMultipleInstancesType() == WorkflowMultiInstanceType.PARALLEL.getCode()) {
+                    vo.setCanRemove(Boolean.FALSE);
+                } else {
+                    //异步不能减签已经审批的和当前审批登录人
+                    //如果人员已经审批了  或者  审批人是当前登陆人 不能移除
+                    if (approveUserIds.contains(user.getId()) || StpUtil.getLoginIdAsLong() == user.getId()) {
+                        vo.setCanRemove(Boolean.FALSE);
+                    } else {
+                        vo.setCanRemove(Boolean.TRUE);
+                    }
+                }
+
+                result.add(vo);
+            }
+
+
+        }
+        return result;
+    }
+
+    @Override
+    public boolean addOrSubSign(AddOrSubSignDto dto) {
+        //排除xml 查出数据
+        WorkflowSchema workflowSchema = workflowSchemaMapper.selectOne(Wrappers.lambdaQuery(WorkflowSchema.class).eq(WorkflowSchema::getId, dto.getSchemaId()).select(x -> !x.getProperty().startsWith(DB_FIELD_XML_PREFIX)));
+
+        if (workflowSchema == null) {
+            throw new MyException("找不到此流程模板!");
+        }
+        //如果当前模板被禁用 无法操作流程
+        if (workflowSchema.getEnabledMark() == EnabledMark.DISABLED.getCode()) {
+            throw new MyException("流程被禁用!");
+        }
+
+        //获取到整个流程模板的配置
+        WorkflowSchemaConfig workflowSchemaConfig = JSONUtil.toBean(workflowSchema.getJsonContent(), WorkflowSchemaConfig.class);
+
+        Task task = taskService.createTaskQuery().taskId(dto.getTaskId()).singleResult();
+
+        Optional<Map<String, Object>> userTaskConfigOp = workflowSchemaConfig.getChildNodeConfig().stream().filter(c -> c.containsValue(task.getTaskDefinitionKey())).findFirst();
+
+        if (!userTaskConfigOp.isPresent()) {
+            throw new MyException("找不到当前节点配置!");
+        }
+        //    将map 转为 java类
+        UserTaskConfig userTaskConfig = Convert.convert(UserTaskConfig.class, userTaskConfigOp.get());
+
+        if (!userTaskConfig.getCountersignConfig().getAddOrRemove()) {
+            throw new MyException("当前节点不允许加减签!");
+        }
+
+        //如果是单实例任务
+        if (userTaskConfig.getCountersignConfig().getMultipleInstancesType() == WorkflowMultiInstanceType.NONE.getCode()) {
+            Object assigneeObj = taskService.getVariable(dto.getTaskId(), WorkflowConstant.TASK_ASSIGNEE_VAR_KEY);
+            List<String> taskAssigneeStrList = StrUtil.split(Convert.toStr(assigneeObj), StringPool.COMMA);
+
+            List<Long> assigneeList = Convert.toList(Long.class, taskAssigneeStrList);
+            assigneeList.removeAll(dto.getUserIds());
+
+            taskService.setVariableLocal(dto.getTaskId(), WorkflowConstant.TASK_ASSIGNEE_VAR_KEY, StrUtil.join(StringPool.COMMA, assigneeList));
+        } else {
+
+            Object assigneeObj = runtimeService.getVariable(task.getProcessInstanceId(), WorkflowConstant.TASK_MULTI_ASSIGNEE_VAR_KEY + task.getTaskDefinitionKey());
+            List<Long> taskAssignee = Convert.toList(Long.class, assigneeObj);
+
+            //取交集 不用动
+            Collection<Long> intersection = CollectionUtil.intersection(taskAssignee, dto.getUserIds());
+
+            //使用交集 与 原审批人 取差集  就是需要减签的成员
+            List<Long> removeUser = CollectionUtil.subtractToList(taskAssignee, intersection);
+            //使用交集 与 新审批人 取差集  就是需要加签的成员
+            List<Long> addUser = CollectionUtil.subtractToList(dto.getUserIds(), intersection);
+
+            int instancesCount = 0;
+            Object allInstances = runtimeService.getVariable(task.getExecutionId(), WorkflowConstant.MULTI_INSTANCE_VAR_KEY);
+
+
+            //如果是串行(异步)
+            if (userTaskConfig.getCountersignConfig().getMultipleInstancesType() == WorkflowMultiInstanceType.SEQUENTIAL.getCode()) {
+                //减签
+                taskAssignee.removeAll(removeUser);
+                instancesCount = Convert.toInt(allInstances) - removeUser.size();
+
+                //加签
+                taskAssignee.addAll(addUser);
+                instancesCount += addUser.size();
+                runtimeService.setVariable(task.getProcessInstanceId(), WorkflowConstant.TASK_MULTI_ASSIGNEE_VAR_KEY + task.getTaskDefinitionKey(), taskAssignee);
+
+            }
+            //同步需要直接开一个任务
+            else {
+                //减签
+                for (Long userId : removeUser) {
+                    Task removeTask = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).taskVariableValueEquals(WorkflowConstant.TASK_ASSIGNEE_VAR_KEY, StrUtil.toString(userId)).singleResult();
+
+                    //获取到 activityinstanceId
+                    HistoricActivityInstance historicActivityInstance = historyService.createHistoricActivityInstanceQuery()
+                            .processInstanceId(removeTask.getProcessInstanceId())
+                            .activityId(task.getTaskDefinitionKey())
+                            .executionId(removeTask.getExecutionId()).singleResult();
+
+                    runtimeService.createProcessInstanceModification(task.getProcessInstanceId())
+                            .cancelActivityInstance(historicActivityInstance.getId())
+                            .execute();
+                }
+                instancesCount = Convert.toInt(allInstances) - removeUser.size();
+                taskAssignee.removeAll(removeUser);
+
+                //加签
+                for (Long userId : addUser) {
+                    runtimeService.createProcessInstanceModification(task.getProcessInstanceId())
+                            .startBeforeActivity(task.getTaskDefinitionKey())
+                            .setVariableLocal(WorkflowConstant.TASK_ASSIGNEE_VAR_KEY, userId)
+                            .execute();
+                }
+                //加签
+                taskAssignee.addAll(addUser);
+                instancesCount += addUser.size();
+                runtimeService.setVariable(task.getProcessInstanceId(), WorkflowConstant.TASK_MULTI_ASSIGNEE_VAR_KEY + task.getTaskDefinitionKey(), taskAssignee);
+            }
+            runtimeService.setVariable(task.getExecutionId(), WorkflowConstant.MULTI_INSTANCE_VAR_KEY, instancesCount);
+
+        }
+        return true;
+    }
+
+    @Override
+    public List<RejectNodeVo> getRejectNode(RejectNodeDto dto) {
+
+        ActivityInstance activityInstance = runtimeService.getActivityInstance(dto.getProcessId());
+        if (activityInstance == null) {
+            throw new MyException("流程已经结束,不允许撤回!");
+        }
+
+        HistoricVariableInstance historicVariableInstance = historyService.createHistoricVariableInstanceQuery().processInstanceId(dto.getProcessId()).variableName(WorkflowConstant.PROCESS_SCHEMA_ID_KEY).singleResult();
+
+        //排除xml 查出数据
+        WorkflowSchema workflowSchema = workflowSchemaMapper.selectOne(Wrappers.lambdaQuery(WorkflowSchema.class).eq(WorkflowSchema::getId, historicVariableInstance.getValue()));
+
+        //获取到整个流程模板的配置
+        WorkflowSchemaConfig workflowSchemaConfig = JSONUtil.toBean(workflowSchema.getJsonContent(), WorkflowSchemaConfig.class);
+
+        List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
+                .processInstanceId(dto.getProcessId())
+                .activityType(WorkflowConstant.BPMN_USER_TASK_TYPE_NAME)
+                .finished()
+                .orderByHistoricActivityInstanceEndTime()
+                .desc()
+                .list();
+
+        String taskDefinitionKey;
+        if (ObjectUtil.isNotNull(dto.getTaskId())) {
+            HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery().taskId(dto.getTaskId()).singleResult();
+            taskDefinitionKey = historicTaskInstance.getTaskDefinitionKey();
+        } else {
+            //一个用户任务也不存在的情况。只有可能是纯粹的脚本任务和开始节点后面直接接外部流程的情况,直接不允许撤回
+            if (list.size() == YesOrNoEnum.NO.getCode()) {
+                throw new MyException("当前流程不允许撤回 ");
+            } else {//正在进行外部流程的子流程运行中
+                throw new MyException("当前流程有其他外部流程 或者 子流程 正在运行,不允许撤回!");
+            }
+//            taskDefinitionKey = activityInstance.getChildActivityInstances()[0].getActivityId();
+        }
+
+//        Task task = taskService.createTaskQuery().taskId(dto.getTaskId()).singleResult();
+
+        Optional<Map<String, Object>> userTaskConfigOp = workflowSchemaConfig.getChildNodeConfig().stream().filter(c -> c.containsValue(taskDefinitionKey)).findFirst();
+
+        if (!userTaskConfigOp.isPresent()) {
+            throw new MyException("找不到当前节点配置!");
+        }
+        //    将map 转为 java类
+        UserTaskConfig userTaskConfig = Convert.convert(UserTaskConfig.class, userTaskConfigOp.get());
+
+        List<RejectNodeVo> voList = new ArrayList<>();
+
+        List<HistoricProcessInstance> subProcess = historyService.createHistoricProcessInstanceQuery()
+                .superProcessInstanceId(dto.getProcessId()).list();
+
+        //当前流程是否有父级流程,就是外部流程或者子流程。外部流程或者子流程不能撤回到开始节点,不新增开始节点
+        if (subProcess.size() < 1) {
+            //获取到当前流程发起人  如果操作人 是发起人 默认新增开始节点
+            Object startUserId = runtimeService.getVariable(dto.getProcessId(), WorkflowConstant.PROCESS_START_USER_ID_KEY);
+            if (StpUtil.getLoginIdAsLong() == Convert.toLong(startUserId)) {
+
+                List<HistoricActivityInstance> startList = historyService.createHistoricActivityInstanceQuery()
+                        .processInstanceId(dto.getProcessId())
+                        .activityType(WorkflowConstant.BPMN_START_EVENT_TYPE_NAME)
+                        .finished()
+                        .orderByHistoricActivityInstanceEndTime()
+                        .desc()
+                        .list();
+
+                HistoricActivityInstance historicActivityInstance = startList.get(0);
+
+                RejectNodeVo vo = new RejectNodeVo();
+                vo.setActivityId(historicActivityInstance.getActivityId());
+                vo.setActivityName(historicActivityInstance.getActivityName());
+                voList.add(vo);
+            }
+        }
+
+        if (list == null || list.size() == 0) {
+            return voList;
+        }
+
+        List<ButtonConfig> buttonConfigs = userTaskConfig.getButtonConfigs();
+
+        if (CollectionUtil.isNotEmpty(buttonConfigs)) {
+            Optional<ButtonConfig> rejectButton = buttonConfigs.stream().filter(ButtonConfig::getChecked).filter(x -> x.getApproveType() == WorkflowApproveType.REJECT.getCode()).filter(x -> x.getButtonOpera().equals(YesOrNoEnum.YES.getCode())).findFirst();
+
+            //如果有配置驳回按钮 并且 设置只能驳回上一节点
+            if (rejectButton.isPresent()) {
+                HistoricActivityInstance historicActivityInstance = list.get(0);
+
+                if (!historicActivityInstance.isCanceled() && !activityInstance.getChildActivityInstances()[0].getActivityId().equals(historicActivityInstance.getActivityId())) {
+                    RejectNodeVo vo = new RejectNodeVo();
+                    vo.setActivityId(historicActivityInstance.getActivityId());
+                    vo.setActivityName(historicActivityInstance.getActivityName());
+                    voList.add(vo);
+                }
+                return voList;
+            }
+        }
+
+
+        for (HistoricActivityInstance historicActivityInstance : list) {
+
+            if (!historicActivityInstance.isCanceled() && !activityInstance.getChildActivityInstances()[0].getActivityId().equals(historicActivityInstance.getActivityId())) {
+                RejectNodeVo vo = new RejectNodeVo();
+                vo.setActivityId(historicActivityInstance.getActivityId());
+                vo.setActivityName(historicActivityInstance.getActivityName());
+                voList.add(vo);
+            }
+
+        }
+        //多次驳回之后需要对返回的节点进行去重操作
+        List<RejectNodeVo> collect = voList.stream().distinct().collect(Collectors.toList());
+        return collect;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean transfer(TransferDto dto) {
+        Object assigneeObj = taskService.getVariableLocal(dto.getTaskId(), WorkflowConstant.TASK_ASSIGNEE_VAR_KEY);
+
+        String newAssignee = StrUtil.toString(assigneeObj).replace(StpUtil.getLoginIdAsString(), dto.getUserId());
+
+        taskService.setVariableLocal(dto.getTaskId(), WorkflowConstant.TASK_ASSIGNEE_VAR_KEY, newAssignee);
+
+        //根据taskid  获取任务信息
+        Task task = taskService.createTaskQuery().taskId(dto.getTaskId()).singleResult();
+        Long schemaId = Convert.toLong(taskService.getVariable(task.getId(), WorkflowConstant.PROCESS_SCHEMA_ID_KEY));
+        //获取当前用户的信息
+        User user = StpUtil.getTokenSession().get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
+        //根据转办人的id获取用户名称
+        List<User> userList = redisUtil.get(GlobalConstant.USER_CACHE_KEY, new TypeReference<List<User>>() {
+        });
+        List<String> collect = userList.stream().filter(u -> dto.getUserId().equals(Convert.toStr(u.getId()))).map(User::getName).collect(Collectors.toList());
+        //转办人名称
+        String newAssigneeName = collect.get(0);
+        //新增流程发起流程记录
+        WorkflowRecord record = new WorkflowRecord();
+        record.setNodeId(task.getId());
+        record.setNodeName(task.getName());
+        record.setNodeType(WorkflowConstant.START_EVENT_TYPE_NAME);
+        record.setProcessId(task.getProcessInstanceId());
+        record.setSchemaId(schemaId);
+        record.setNodeMultiType(WorkflowMultiInstanceType.NONE.getCode());
+        record.setRecordTime(LocalDateTime.now());
+        //[操作人名称]将[节点名称] 转交给[被作人名称]办理
+        String message = "【" + user.getName() + "】将【" + task.getName() + "】转交给【" + newAssigneeName + "】办理";
+        record.setMessage(message);
+
+        workflowRecordMapper.insert(record);
+        return true;
+    }
+
+    @Override
+    public GetCountVo getCount() {
+        GetCountVo vo = new GetCountVo();
+//        SaSession tokenSession = StpUtil.getTokenSession();
+//        User user = tokenSession.get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
+
+        TaskQuery taskQuery = taskService.createTaskQuery()
+                .active()
+                .taskVariableValueEquals(WorkflowConstant.TASK_IS_APPOINT_APPROVE, YesOrNoEnum.NO.getCode())
+                .processVariableValueEquals(WorkflowConstant.PROCESS_ISRECYCLE_FLAG_KEY, WorkflowIsRecycleType.NO.getCode())
+                .taskVariableValueLike(WorkflowConstant.TASK_ASSIGNEE_VAR_KEY, StringPool.PERCENT + StpUtil.getLoginIdAsLong() + StringPool.PERCENT);
+
+        vo.setPendingCount(taskQuery.count());
+
+
+        LambdaQueryWrapper<WorkflowDelegate> delegateQueryWrapper = Wrappers.lambdaQuery(WorkflowDelegate.class).like(WorkflowDelegate::getDelegateUserIds, StpUtil.getLoginIdAsLong());
+
+        vo.setDelegateCount(workflowDelegateMapper.selectCount(delegateQueryWrapper));
+
+
+        LambdaQueryWrapper<WorkflowApproveRecord> recordQueryWrapper = Wrappers.lambdaQuery(WorkflowApproveRecord.class).eq(WorkflowApproveRecord::getApproveUserId, StpUtil.getLoginIdAsLong());
+        vo.setFinishedCount(approveRecordService.count(recordQueryWrapper));
+
+
+        return vo;
+    }
+
+
+    /**
+     * 根据流程id  获取流程流转信息
+     *
+     * @param processInstanceId
+     * @return
+     */
+    private List<ProcessRecordListVo> getProcessRecordListVos(String processInstanceId, int onlySelf) {
+
+        User user = StpUtil.getTokenSession().get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
+        List<Long> roleIds = StpUtil.getTokenSession().get(GlobalConstant.LOGIN_USER_ROLE_ID_KEY, new ArrayList<>());
+        LambdaQueryWrapper<WorkflowRecord> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+        if (onlySelf == YesOrNoEnum.YES.getCode()) {//仅查看本人
+            if (roleIds.contains(GlobalConstant.SUPER_ADMIN_ROLE_ID)) {//管理员数据
+                lambdaQueryWrapper.eq(WorkflowRecord::getProcessId, processInstanceId)
+                        .orderByAsc(WorkflowRecord::getRecordTime)
+                        .like(WorkflowRecord::getMessage, user.getName())
+                        .or()
+                        .like(WorkflowRecord::getMessage, "流程结束")
+                        .eq(WorkflowRecord::getProcessId, processInstanceId)
+                        .or()
+                        .like(WorkflowRecord::getMessage, "脚本节点")
+                        .eq(WorkflowRecord::getCreateUserId, StpUtil.getLoginIdAsLong())//脚本任务
+                        .eq(WorkflowRecord::getProcessId, processInstanceId);
+            } else {//其他人数据
+                lambdaQueryWrapper.eq(WorkflowRecord::getProcessId, processInstanceId)
+                        .orderByAsc(WorkflowRecord::getRecordTime)
+                        .eq(WorkflowRecord::getCreateUserId, StpUtil.getLoginIdAsLong())
+                        .like(WorkflowRecord::getMessage, user.getName())
+                        .or()
+                        .like(WorkflowRecord::getMessage, user.getName())
+                        .eq(WorkflowRecord::getProcessId, processInstanceId)
+                        .or()
+                        .like(WorkflowRecord::getMessage, "脚本节点")
+                        .eq(WorkflowRecord::getCreateUserId, StpUtil.getLoginIdAsLong())//脚本任务
+                        .eq(WorkflowRecord::getProcessId, processInstanceId);
+            }
+        } else {
+            lambdaQueryWrapper.eq(WorkflowRecord::getProcessId, processInstanceId)
+                    .orderByAsc(WorkflowRecord::getRecordTime);
+        }
+
+        List<WorkflowRecord> workflowRecords = workflowRecordMapper.selectList(lambdaQueryWrapper);
+
+        List<ProcessRecordListVo> recordListVos = new ArrayList<>(workflowRecords.size());
+        for (WorkflowRecord workflowRecord : workflowRecords) {
+            ProcessRecordListVo recordListVo = new ProcessRecordListVo();
+            recordListVo.setNodeType(workflowRecord.getNodeType());
+            recordListVo.setNodeName(workflowRecord.getNodeName());
+            recordListVo.setComment(workflowRecord.getMessage());
+            recordListVo.setStartTime(workflowRecord.getRecordTime());
+            recordListVo.setCirculateMessage(workflowRecord.getCirculateMessage());
+            recordListVos.add(recordListVo);
+        }
+        return recordListVos;
+    }
+
+
+    private void invokeAutoAgree(String processInstanceId, Long schemaId, WorkflowSchemaConfig workflowSchemaConfig, List<Task> taskList) {
+
+        if (taskList.size() == 0) {
+        } else if (taskList.size() == 1) {
+            Task task = taskList.get(0);
+            Optional<Map<String, Object>> userTaskConfigMap = workflowSchemaConfig.getChildNodeConfig().stream().filter(x -> x.containsValue(task.getTaskDefinitionKey())).findFirst();
+            User user = StpUtil.getTokenSession().get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
+            if (!userTaskConfigMap.isPresent()) {
+                throw new MyException("当前任务没有开始节点");
+            }
+            //将map 转为 java类
+            UserTaskConfig userTaskConfig = Convert.convert(UserTaskConfig.class, userTaskConfigMap.get());
+            List<Integer> userAutoAgree = userTaskConfig.getAutoAgreeRule();
+            List<Integer> processAutoAgree = workflowSchemaConfig.getProcessConfig().getAutoAgreeRule();
+
+            if (userAutoAgree != null && userAutoAgree.size() > 0) {
+                isAutoAgree(processInstanceId, schemaId, workflowSchemaConfig, task, user, userAutoAgree);
+                return;
+            }
+            if (processAutoAgree != null && processAutoAgree.size() > 0) {
+                isAutoAgree(processInstanceId, schemaId, workflowSchemaConfig, task, user, processAutoAgree);
+            }
+        } else {
+            for (Task task : taskList) {
+                Optional<Map<String, Object>> userTaskConfigMap = workflowSchemaConfig.getChildNodeConfig().stream().filter(x -> x.containsValue(task.getTaskDefinitionKey())).findFirst();
+                User user = StpUtil.getTokenSession().get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
+                if (!userTaskConfigMap.isPresent()) {
+                    throw new MyException("当前任务没有开始节点");
+                }
+                //将map 转为 java类
+                UserTaskConfig userTaskConfig = Convert.convert(UserTaskConfig.class, userTaskConfigMap.get());
+                List<Integer> userAutoAgree = userTaskConfig.getAutoAgreeRule();
+                List<Integer> processAutoAgree = workflowSchemaConfig.getProcessConfig().getAutoAgreeRule();
+
+                if (userAutoAgree != null && userAutoAgree.size() > 0) {
+                    isAutoAgree(processInstanceId, schemaId, workflowSchemaConfig, task, user, userAutoAgree);
+                    return;
+                }
+                if (processAutoAgree != null && processAutoAgree.size() > 0) {
+                    isAutoAgree(processInstanceId, schemaId, workflowSchemaConfig, task, user, processAutoAgree);
+                }
+            }
+        }
+    }
+
+    private void isAutoAgree(String processInstanceId, Long schemaId, WorkflowSchemaConfig workflowSchemaConfig, Task task, User user, List<Integer> autoAgreeConfig) {
+        Object approveUserIdsObj = taskService.getVariable(task.getId(), WorkflowConstant.TASK_ASSIGNEE_VAR_KEY);
+        Object startUserIdObj = taskService.getVariable(task.getId(), WorkflowConstant.PROCESS_START_USER_ID_KEY);
+        List<Long> approveUserIds = Arrays.stream(Convert.toStr(approveUserIdsObj).split(StringPool.COMMA)).map(Convert::toLong).collect(Collectors.toList());
+        Long startUserId = Convert.toLong(startUserIdObj);
+        String opinion = StringPool.EMPTY;
+        boolean isAgree = Boolean.FALSE;
+
+        List<String> opinions = new ArrayList<>();//所有选择的自动同意规则
+        List<Long> allUserIds = new ArrayList<>();//所有自动同意审批的用户id
+        //新增流程发起流程记录
+        WorkflowRecord record = new WorkflowRecord();
+        //候选审批人包含流程任务发起人
+        if (autoAgreeConfig.contains(WorkflowAutoAgreeType.APPROVED_INCLUDE_INITIATOR.getCode())) {
+            if (approveUserIds.contains(startUserId)) {
+                allUserIds.add(startUserId);
+                taskService.createComment(task.getId(), task.getProcessInstanceId(), "候选审批人包含流程任务发起人---自动同意");
+                //自动同意缓存流程审批人记录
+                WorkFlowUtil.cacheTaskAssigneeRecord(processInstanceId, task.getId(), startUserId);
+                opinion = "候选审批人包含流程任务发起人";
+                opinions.add(opinion);
+                isAgree = Boolean.TRUE;
+            }
+        }
+        //候选审批人包含上一节点审批人
+        if (autoAgreeConfig.contains(WorkflowAutoAgreeType.APPROVED_INCLUDE_PREV.getCode())) {
+            //上一节点审批人 都是当前操作人。  因为此方法 只会在 发起  和  审批节点 执行
+            if (approveUserIds.contains(StpUtil.getLoginIdAsLong())) {
+                allUserIds.add(StpUtil.getLoginIdAsLong());
+                taskService.createComment(task.getId(), task.getProcessInstanceId(), "候选审批人包含上一节点审批人---自动同意");
+                //自动同意缓存流程审批人记录
+                WorkFlowUtil.cacheTaskAssigneeRecord(processInstanceId, task.getId(), StpUtil.getLoginIdAsLong());
+                opinion = "候选审批人包含上一节点审批人";
+                opinions.add(opinion);
+                isAgree = Boolean.TRUE;
+            }
+        }
+        String approveName = "";
+        if (autoAgreeConfig.contains(WorkflowAutoAgreeType.APPROVED_IN_PROCESS.getCode())) {
+
+            Map<String, List<Long>> taskAssigneeRecordMap = redisUtil.get(processInstanceId + WorkflowConstant.TASK_ASSIGNEE_RECORD_VAR_KEY, new TypeReference<Map<String, List<Long>>>() {
+            });
+
+            //如果为空 代表是开始节点  还未有审批人
+            if (taskAssigneeRecordMap == null) {
+                if (approveUserIds.contains(Convert.toLong(startUserId))) {
+                    allUserIds.add(Convert.toLong(startUserId));
+                    taskService.createComment(task.getId(), task.getProcessInstanceId(), "候选审批人在此流程中审批过---自动同意");
+                    WorkFlowUtil.cacheTaskAssigneeRecord(processInstanceId, task.getId(), startUserId);
+                    opinion = "候选审批人在此流程中审批过";
+                    opinions.add(opinion);
+                    isAgree = Boolean.TRUE;
+                }
+            } else {
+                Collection<List<Long>> assigneeList = taskAssigneeRecordMap.values();
+                List<Long> allAssignee = new ArrayList<>();
+                allAssignee.add(startUserId);
+                for (List<Long> assignee : assigneeList) {
+                    allAssignee.addAll(assignee);
+                }
+                //并集 就是在流程中审批过的人
+                Collection<Long> intersection = CollectionUtil.intersection(allAssignee, approveUserIds);
+                //获取自动审批的人员名称,给流程信息使用
+                List<Long> list = intersection.stream().collect(Collectors.toList());
+                allUserIds.addAll(list);
+                if (intersection.size() > 0) {
+                    //在流转到下一个任务前设置好流程信息时间
+                    taskService.createComment(task.getId(), task.getProcessInstanceId(), "候选审批人在此流程中审批过---自动同意");
+                    List<Long> assigneeInApprove = new ArrayList<>(intersection);
+                    WorkFlowUtil.cacheTaskAssigneeRecord(processInstanceId, task.getId(), assigneeInApprove.get(0));
+                    isAgree = Boolean.TRUE;
+                    opinion = "候选审批人在此流程中审批过";
+                    opinions.add(opinion);
+                }
+            }
+        }
+        if (isAgree) {
+            //自动同意之后完成本次任务
+            record.setRecordTime(LocalDateTime.now());
+            taskService.complete(task.getId());
+            List<Task> list = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list();
+            String allOpinions = StringPool.EMPTY;
+            if (opinions.size() > 0) {
+                String chineseDot = "、";
+                allOpinions = StrUtil.join(chineseDot, opinions);
+            }
+            approveName = WorkFlowUtil.getAllUserNamesByIds(allUserIds);
+            //如果找不到任务了 默认流程已经结束
+            if (list.size() > 0) {
+                String allNextTaskName = StrUtil.join(StringPool.SPACE, list.parallelStream().map(t -> "【" + t.getName() + "】").collect(Collectors.toList()));
+
+                String message = "【" + approveName + "】【自动同意】 审批, 审批意见为:“【" + allOpinions + "】”,由【" + task.getName() + "】流转到 " + allNextTaskName;
+                addProcessRecord(task, schemaId, message, record);
+                // 如果还有用户任务  则递归调用
+                invokeAutoAgree(processInstanceId, schemaId, workflowSchemaConfig, list);
+            } else {
+                String message = "【" + approveName + "】【自动同意】 审批, 审批意见为:“【" + allOpinions + "】”,由【" + task.getName() + "】流转到 结束节点";
+                addProcessRecord(task, schemaId, message, record);
+            }
+        }
+
+    }
+
+
+    /**
+     * 判断是否由需要指定审批人 老版
+     *
+     * @param workflowSchemaConfig
+     * @param processInstanceId
+     * @return
+     */
+    private ImmutableTriple<String, Boolean, Boolean> isPrevChooseApproveBackUp(WorkflowSchemaConfig workflowSchemaConfig, String processInstanceId, List<Task> list) {
+
+        //left==taskId | middle == 是否需要指定 | right == 是否多实例
+        //如果一个任务都没有 证明了流程走完了  如果list 大于1  也证明任务的下一节点是多实例  多实例无法指定审批人
+        if (list.size() == 0) {
+            return new ImmutableTriple<>("", Boolean.FALSE, Boolean.FALSE);
+        } else if (list.size() > 1) {
+            return new ImmutableTriple<>("", Boolean.FALSE, Boolean.TRUE);
+        } else {
+            Task task = list.get(0);
+
+            Optional<Map<String, Object>> userTaskConfigMap = workflowSchemaConfig.getChildNodeConfig().stream().filter(x -> x.containsValue(task.getTaskDefinitionKey())).findFirst();
+            if (!userTaskConfigMap.isPresent()) {
+                throw new MyException("找不到下一个用户任务的配置!");
+            }
+            UserTaskConfig userTaskConfig = Convert.convert(UserTaskConfig.class, userTaskConfigMap.get());
+            //只有非会签流程  才需要判断 是否指定审批人 是否无对应处理人  判断完 前两者 再判断是否自动同意
+            if (userTaskConfig.getCountersignConfig().getMultipleInstancesType() == WorkflowMultiInstanceType.NONE.getCode()) {
+                VariableInstance variableInstance = runtimeService.createVariableInstanceQuery().taskIdIn(task.getId()).variableName(WorkflowConstant.TASK_ASSIGNEE_VAR_KEY).singleResult();
+                //如果审批人变量不为空
+                if (variableInstance != null) {
+                    if (
+                            userTaskConfig.getIsPrevChooseNext() == WorkflowIsPrevChooseNextType.PREV.getCode() ||
+                                    workflowSchemaConfig.getProcessConfig().getIsPrevChooseNext() == WorkflowIsPrevChooseNextType.PREV.getCode()
+                    ) {
+                        return new ImmutableTriple<>(task.getId(), Boolean.TRUE, Boolean.FALSE);
+                    }
+
+                } else {
+                    //
+                    if (userTaskConfig.getNoHandler() == WorkflowNoHandlerType.PREV.getCode() ||
+                            workflowSchemaConfig.getProcessConfig().getNoHandler() == WorkflowNoHandlerType.PREV.getCode()
+                    ) {
+                        return new ImmutableTriple<>(task.getId(), Boolean.TRUE, Boolean.FALSE);
+                    }
+                }
+                return new ImmutableTriple<>(task.getId(), Boolean.FALSE, Boolean.FALSE);
+            } else {
+                return new ImmutableTriple<>("", Boolean.FALSE, Boolean.TRUE);
+            }
+        }
+    }
+
+    /**
+     * 判断是否由需要指定审批人
+     *
+     * @param workflowSchemaConfig
+     * @param list
+     * @return
+     */
+    private List<LaunchAndApproveVo> isPrevChooseApprove(WorkflowSchemaConfig workflowSchemaConfig, List<Task> list, VariableMap variableMap) {
+        List<LaunchAndApproveVo> voList = new ArrayList<>();
+
+        //left==taskId | middle == 是否需要指定 | right == 是否多实例
+        //如果一个任务都没有 证明了流程走完了  如果list 大于1  也证明任务的下一节点是多实例  多实例无法指定审批人
+        if (list.size() == 0) {
+            return voList;
+        } else if (list.size() > 1) {
+            String[] taskIds = list.stream().map(Task::getId).toArray(String[]::new);
+            List<VariableInstance> variableInstanceList = runtimeService.createVariableInstanceQuery().taskIdIn(taskIds).variableName(WorkflowConstant.TASK_ASSIGNEE_VAR_KEY).list();
+            for (Task task : list) {
+                LaunchAndApproveVo vo = new LaunchAndApproveVo();
+                Optional<Map<String, Object>> userTaskConfigMap = workflowSchemaConfig.getChildNodeConfig().stream().filter(x -> x.containsValue(task.getTaskDefinitionKey())).findFirst();
+                if (!userTaskConfigMap.isPresent()) {
+                    throw new MyException("找不到下一个用户任务的配置!");
+                }
+                UserTaskConfig userTaskConfig = Convert.convert(UserTaskConfig.class, userTaskConfigMap.get());
+                Optional<VariableInstance> variableInstanceOptional = variableInstanceList.stream()
+                        .filter(v -> v.getTaskId().equals(task.getId()))
+                        .filter(v -> v.getName().equals(WorkflowConstant.TASK_ASSIGNEE_VAR_KEY))
+                        .findFirst();
+
+                //只有非会签流程  才需要判断 是否指定审批人 是否无对应处理人  判断完 前两者 再判断是否自动同意
+                if (userTaskConfig.getCountersignConfig().getMultipleInstancesType() == WorkflowMultiInstanceType.NONE.getCode()) {
+
+                    //如果设置了指定审批人
+                    if (
+                            userTaskConfig.getIsPrevChooseNext() == WorkflowIsPrevChooseNextType.PREV.getCode() ||
+                                    workflowSchemaConfig.getProcessConfig().getIsPrevChooseNext() == WorkflowIsPrevChooseNextType.PREV.getCode()
+                    ) {
+                        vo.setTaskName(task.getName());
+                        vo.setTaskId(task.getId());
+                        vo.setIsAppoint(Boolean.TRUE);
+                        vo.setIsMultiInstance(Boolean.FALSE);
+                        vo.setProvisionalApprover(userTaskConfig.getProvisionalApprover());
+                        variableInstanceOptional.ifPresent(var -> {
+                            vo.setApproveUserIds(Convert.toStr(var.getValue()));
+                        });
+                        voList.add(vo);
+
+
+                        //如果是需要指定审批人 默认设置变量
+                        taskService.setVariableLocal(task.getId(), WorkflowConstant.TASK_IS_APPOINT_APPROVE, YesOrNoEnum.YES.getCode());
+                        //默认定时10分钟  如果不指定审批人 就会使用原审批人
+                        redisUtil.set(task.getId() + StringPool.UNDERSCORE + WorkflowConstant.TASK_IS_APPOINT_APPROVE, task.getId(), 10 * 60);
+//                            redisUtil.set(GlobalConstant.CAPTCHA + StringPool.UNDERSCORE + mobile, code, 6000L);
+                        continue;
+                    }
+
+                    //如果没有设置过审批人  需要走无对应处理人逻辑
+                    if (userTaskConfig.getApproverConfigs() == null || userTaskConfig.getApproverConfigs().size() == 0) {
+                        // 如果需要指定审批人
+                        if (userTaskConfig.getNoHandler() == WorkflowNoHandlerType.PREV.getCode()) {
+                            vo.setTaskName(task.getName());
+                            vo.setTaskId(task.getId());
+                            vo.setIsAppoint(Boolean.TRUE);
+                            vo.setIsMultiInstance(Boolean.FALSE);
+                            vo.setProvisionalApprover(userTaskConfig.getProvisionalApprover());
+
+                            variableInstanceOptional.ifPresent(var -> {
+                                vo.setApproveUserIds(Convert.toStr(var.getValue()));
+                            });
+                            voList.add(vo);
+
+                            //如果是需要指定审批人 默认设置变量
+                            taskService.setVariableLocal(task.getId(), WorkflowConstant.TASK_IS_APPOINT_APPROVE, YesOrNoEnum.YES.getCode());
+                            //默认定时10分钟  如果不指定审批人 就会使用原审批人
+                            redisUtil.set(task.getId() + StringPool.UNDERSCORE + WorkflowConstant.TASK_IS_APPOINT_APPROVE, task.getId(), 10 * 60);
+                            continue;
+                        } else {
+                            List<UserRoleRelation> userRoleRelations = redisUtil.get(GlobalConstant.USER_ROLE_RELATION_CACHE_KEY, new TypeReference<List<UserRoleRelation>>() {
+                            });
+                            //获取超级管理员成员
+                            List<Long> adminUserIds = userRoleRelations.stream().filter(x -> x.getRoleId().equals(GlobalConstant.SUPER_ADMIN_ROLE_ID)).map(UserRoleRelation::getUserId).collect(Collectors.toList());
+                            taskService.setVariableLocal(task.getId(), WorkflowConstant.TASK_ASSIGNEE_VAR_KEY, StrUtil.join(StringPool.COMMA, adminUserIds));
+                        }
+                    }
+                    vo.setTaskName(task.getName());
+                    vo.setTaskId(task.getId());
+                    vo.setIsAppoint(Boolean.FALSE);
+                    vo.setIsMultiInstance(Boolean.FALSE);
+                    vo.setProvisionalApprover(userTaskConfig.getProvisionalApprover());
+                    taskService.setVariableLocal(task.getId(), WorkflowConstant.TASK_IS_APPOINT_APPROVE, YesOrNoEnum.NO.getCode());
+                    voList.add(vo);
+
+                } else {
+                    vo.setTaskName(task.getName());
+                    vo.setTaskId(task.getId());
+                    vo.setIsAppoint(Boolean.FALSE);
+                    vo.setIsMultiInstance(Boolean.TRUE);
+                    vo.setProvisionalApprover(userTaskConfig.getProvisionalApprover());
+                    taskService.setVariableLocal(task.getId(), WorkflowConstant.TASK_IS_APPOINT_APPROVE, YesOrNoEnum.NO.getCode());
+                    voList.add(vo);
+                }
+
+                //记录一下需要发送消息(不需要指定审批人的)的任务id
+//                if (variableInstanceOptional.isPresent()) {
+//
+//                    List<String> approveIds = ListUtil.toList(Convert.toStr(variableInstanceOptional.get().getValue()).split(StringPool.COMMA));
+//
+//                    NoticePolicyParam param = new NoticePolicyParam();
+//                    param.setNoticeUserIds(Convert.toList(Long.class, approveIds));
+//                    param.setTaskId(task.getId());
+//                    param.setTaskName(task.getName());
+//                    param.setProcessId(task.getProcessInstanceId());
+//                    param.setTaskName(task.getName());
+//                    param.setSchemaId(MapUtil.get(variableMap, WorkflowConstant.PROCESS_SCHEMA_ID_KEY, Long.class));
+//                    param.setSchemaName(MapUtil.get(variableMap, WorkflowConstant.PROCESS_SCHEMA_NAME_KEY, String.class));
+//                    param.setStartUserName(MapUtil.get(variableMap, WorkflowConstant.PROCESS_START_USER_NAME_KEY, String.class));
+//
+//                    param.setNoticePolicyConfigs(userTaskConfig.getNoticePolicyConfigs());
+//                    WorkFlowUtil.sendApproveNoticePolicy(param, task.getName());
+//                }
+
+            }
+
+            return voList;
+        } else {
+            Task task = list.get(0);
+
+            LaunchAndApproveVo vo = new LaunchAndApproveVo();
+
+            Optional<Map<String, Object>> userTaskConfigMap = workflowSchemaConfig.getChildNodeConfig().stream().filter(x -> x.containsValue(task.getTaskDefinitionKey())).findFirst();
+            if (!userTaskConfigMap.isPresent()) {
+                throw new MyException("找不到下一个用户任务的配置!");
+            }
+            UserTaskConfig userTaskConfig = Convert.convert(UserTaskConfig.class, userTaskConfigMap.get());
+            VariableInstance variableInstance = runtimeService.createVariableInstanceQuery().taskIdIn(task.getId()).variableName(WorkflowConstant.TASK_ASSIGNEE_VAR_KEY).singleResult();
+
+            //只有非会签流程  才需要判断 是否指定审批人 是否无对应处理人  判断完 前两者 再判断是否自动同意
+            if (userTaskConfig.getCountersignConfig().getMultipleInstancesType() == WorkflowMultiInstanceType.NONE.getCode()) {
+
+                if (
+                        userTaskConfig.getIsPrevChooseNext() == WorkflowIsPrevChooseNextType.PREV.getCode() ||
+                                workflowSchemaConfig.getProcessConfig().getIsPrevChooseNext() == WorkflowIsPrevChooseNextType.PREV.getCode()
+                ) {
+                    vo.setTaskName(task.getName());
+                    vo.setTaskId(task.getId());
+                    vo.setIsAppoint(Boolean.TRUE);
+                    vo.setIsMultiInstance(Boolean.FALSE);
+                    vo.setProvisionalApprover(userTaskConfig.getProvisionalApprover());
+                    if (variableInstance != null) {
+                        vo.setApproveUserIds(Convert.toStr(variableInstance.getValue()));
+                    } else {
+                        vo.setProvisionalApprover(Boolean.TRUE);
+                    }
+
+                    voList.add(vo);
+
+                    //如果是需要指定审批人 默认设置变量
+                    taskService.setVariableLocal(task.getId(), WorkflowConstant.TASK_IS_APPOINT_APPROVE, YesOrNoEnum.YES.getCode());
+                    //默认定时10分钟  如果不指定审批人 就会使用原审批人
+                    redisUtil.set(task.getId() + StringPool.UNDERSCORE + WorkflowConstant.TASK_IS_APPOINT_APPROVE, task.getId(), 10 * 60);
+                    return voList;
+                }
+
+                //如果没有设置过审批人  需要走无对应处理人逻辑
+                if (userTaskConfig.getApproverConfigs() == null || userTaskConfig.getApproverConfigs().size() == 0) {
+
+                    if (userTaskConfig.getNoHandler() == WorkflowNoHandlerType.PREV.getCode()
+                    ) {
+                        vo.setTaskName(task.getName());
+                        vo.setTaskId(task.getId());
+                        vo.setIsAppoint(Boolean.TRUE);
+                        vo.setIsMultiInstance(Boolean.FALSE);
+                        vo.setProvisionalApprover(userTaskConfig.getProvisionalApprover());
+
+                        if (variableInstance != null) {
+                            vo.setApproveUserIds(Convert.toStr(variableInstance.getValue()));
+                        } else {
+                            vo.setProvisionalApprover(Boolean.TRUE);
+                        }
+                        voList.add(vo);
+
+                        //如果是需要指定审批人 默认设置变量
+                        taskService.setVariableLocal(task.getId(), WorkflowConstant.TASK_IS_APPOINT_APPROVE, YesOrNoEnum.YES.getCode());
+                        //默认定时10分钟  如果不指定审批人 就会使用原审批人
+                        redisUtil.set(task.getId() + StringPool.UNDERSCORE + WorkflowConstant.TASK_IS_APPOINT_APPROVE, task.getId(), 10 * 60);
+                        return voList;
+                    } else {
+                        List<UserRoleRelation> userRoleRelations = redisUtil.get(GlobalConstant.USER_ROLE_RELATION_CACHE_KEY, new TypeReference<List<UserRoleRelation>>() {
+                        });
+                        //获取超级管理员成员
+                        List<Long> adminUserIds = userRoleRelations.stream().filter(x -> x.getRoleId().equals(GlobalConstant.SUPER_ADMIN_ROLE_ID)).map(UserRoleRelation::getUserId).collect(Collectors.toList());
+                        taskService.setVariableLocal(task.getId(), WorkflowConstant.TASK_ASSIGNEE_VAR_KEY, StrUtil.join(StringPool.COMMA, adminUserIds));
+                    }
+                }
+                vo.setTaskName(task.getName());
+                vo.setTaskId(task.getId());
+                vo.setIsAppoint(Boolean.FALSE);
+                vo.setIsMultiInstance(Boolean.FALSE);
+                vo.setProvisionalApprover(userTaskConfig.getProvisionalApprover());
+                voList.add(vo);
+                taskService.setVariableLocal(task.getId(), WorkflowConstant.TASK_IS_APPOINT_APPROVE, YesOrNoEnum.NO.getCode());
+
+
+            } else {
+                vo.setTaskName(task.getName());
+                vo.setTaskId(task.getId());
+                vo.setIsAppoint(Boolean.FALSE);
+                vo.setIsMultiInstance(Boolean.TRUE);
+                vo.setProvisionalApprover(userTaskConfig.getProvisionalApprover());
+                voList.add(vo);
+                taskService.setVariableLocal(task.getId(), WorkflowConstant.TASK_IS_APPOINT_APPROVE, YesOrNoEnum.NO.getCode());
+
+
+            }
+            //如果审批人变量不为空  并且不需要指定审批人 就发送消息
+//            if (variableInstance != null) {
+//                List<String> approveIds = ListUtil.toList(Convert.toStr(variableInstance.getValue()).split(StringPool.COMMA));
+//
+//                NoticePolicyParam param = new NoticePolicyParam();
+//                param.setNoticeUserIds(Convert.toList(Long.class, approveIds));
+//                param.setTaskId(task.getId());
+//                param.setTaskName(task.getName());
+//                param.setProcessId(task.getProcessInstanceId());
+//                param.setTaskName(task.getName());
+//                param.setSchemaId(MapUtil.get(variableMap, WorkflowConstant.PROCESS_SCHEMA_ID_KEY, Long.class));
+//                param.setSchemaName(MapUtil.get(variableMap, WorkflowConstant.PROCESS_SCHEMA_NAME_KEY, String.class));
+//                param.setStartUserName(MapUtil.get(variableMap, WorkflowConstant.PROCESS_START_USER_NAME_KEY, String.class));
+//                param.setNoticePolicyConfigs(userTaskConfig.getNoticePolicyConfigs());
+//                WorkFlowUtil.sendApproveNoticePolicy(param, task.getName());
+//
+//            }
+
+
+            return voList;
+
+        }
+    }
+
+    /**
+     * 添加流程记录
+     */
+    private void addProcessRecord(Task task, Long schemaId, String message, WorkflowRecord record) {
+
+        IWorkflowRecordService workflowRecordService = SpringUtil.getBean(IWorkflowRecordService.class);
+        //新增流程发起流程记录
+        record.setNodeId(task.getId());
+        record.setNodeName(task.getName());
+        record.setNodeType(WorkflowConstant.START_EVENT_TYPE_NAME);
+        record.setProcessId(task.getProcessInstanceId());
+        record.setSchemaId(schemaId);
+        record.setNodeMultiType(WorkflowMultiInstanceType.NONE.getCode());
+
+        record.setMessage(message);
+
+        workflowRecordService.save(record);
+
+
+    }
+
+
+    /**
+     * 记录开始节点
+     *
+     * @param workflowSchema
+     * @param startNodeConfig
+     * @param processInstance
+     */
+    private void startNodeRecord(WorkflowSchema workflowSchema, StartNodeConfig startNodeConfig, ProcessInstance processInstance, User user) {
+
+        //新增流程发起流程记录
+        WorkflowRecord startRecord = new WorkflowRecord();
+        startRecord.setNodeId(startNodeConfig.getId());
+        startRecord.setNodeName(startNodeConfig.getName());
+        startRecord.setNodeType(WorkflowConstant.START_EVENT_TYPE_NAME);
+        startRecord.setProcessId(processInstance.getId());
+        startRecord.setSchemaId(workflowSchema.getId());
+        startRecord.setNodeMultiType(WorkflowMultiInstanceType.NONE.getCode());
+        startRecord.setRecordTime(LocalDateTime.now());
+        startRecord.setMessage("【" + user.getName() + "】 创建流程");
+
+        workflowRecordMapper.insert(startRecord);
+    }
+
+    /**
+     * 构建流程默认参数 (全局变量 发起人id、发起人名、模板id 、模板名、页面配置参数值、流水号)等
+     *
+     * @param workflowSchema
+     * @return
+     */
+    private VariableMap initDefaultParam(WorkflowSchema workflowSchema, Map<String, Object> processParam, long count) {
+
+        User user = StpUtil.getTokenSession().get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
+
+        //设定全局变量 发起人id、发起人名、模板id 、模板名、页面配置参数值、流水号
+        return Variables.createVariables()
+                .putValue(WorkflowConstant.PROCESS_START_USER_ID_KEY, user.getId())
+                .putValue(WorkflowConstant.PROCESS_START_USER_NAME_KEY, user.getName())
+                .putValue(WorkflowConstant.PROCESS_START_USER_POST_ID_KEY, user.getPostId())
+                .putValue(WorkflowConstant.PROCESS_SCHEMA_ID_KEY, workflowSchema.getId())
+                .putValue(WorkflowConstant.PROCESS_SCHEMA_NAME_KEY, workflowSchema.getName())
+                .putValue(WorkflowConstant.PROCESS_PARAM_KEY, processParam)
+                .putValue(WorkflowConstant.PROCESS_ISRECYCLE_FLAG_KEY, WorkflowIsRecycleType.NO.getCode())
+                .putValue(WorkflowConstant.PROCESS_SERIAL_NUMBER_KEY, count + 1);
+    }
+
+    /***
+     * 表单赋值逻辑
+     * @param formData 表单数据
+     * @param workflowSchema
+     * @param workflowSchemaConfig
+     */
+    private void initFormAssignment(Map<String, Map<String, Object>> formData, WorkflowSchema workflowSchema, WorkflowSchemaConfig workflowSchemaConfig, Map<String, Object> processParam) {
+        //获取所有节点配置
+        List<Map<String, Object>> childNodeConfig = workflowSchemaConfig.getChildNodeConfig();
+        Optional<Map<String, Object>> startNodeMap = childNodeConfig.stream().filter(x -> x.containsValue(WorkflowConstant.BPMN_XML_START_EVENT_TYPE_NAME)).findFirst();
+
+        if (!startNodeMap.isPresent()) {
+            throw new MyException("当前任务没有开始节点");
+        }
+        //将map 转为 java类
+        StartNodeConfig startNodeConfig = Convert.convert(StartNodeConfig.class, startNodeMap.get());
+
+
+        WorkFlowUtil.invokeFormAssignment(formData, startNodeConfig.getAssignmentConfig(), startNodeConfig.getFormConfigs(), processParam);
+
+
+    }
+
+    /**
+     * 构建传阅人
+     *
+     * @param task
+     * @param circulateConfigs
+     * @param workflowSchemaConfig
+     * @param userTaskConfig
+     */
+    private String initCirculate(Task task, List<MemberConfig> circulateConfigs, WorkflowSchemaConfig workflowSchemaConfig, UserTaskConfig userTaskConfig, Map<String, Object> variableMaps) {
+        //获取到需要追加的传阅人
+        List<Long> appendUserTaskCirculated = WorkFlowUtil.getUserIdsByMemberConfig(circulateConfigs, workflowSchemaConfig.getChildNodeConfig(), task.getProcessInstanceId());
+
+        List<WorkflowCirculated> circulatedList = circulatedService.list(Wrappers.lambdaQuery(WorkflowCirculated.class).eq(WorkflowCirculated::getTaskId, task.getId()));
+
+        //获取当前用户的信息
+        User user = StpUtil.getTokenSession().get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
+        Long schemaId = Convert.toLong(taskService.getVariable(task.getId(), WorkflowConstant.PROCESS_SCHEMA_ID_KEY));
+
+        String circulatedName = "";//添加的传阅人姓名
+        String circulateMessage = "";//传阅信息
+        //获取用户id对应的用户名
+        circulatedName = getAllUserNamesByIds(appendUserTaskCirculated);
+        if (circulatedList == null || circulatedList.size() == 0) {
+
+            circulatedList = new ArrayList<>();
+            for (Long userId : appendUserTaskCirculated) {
+                WorkflowCirculated workflowCirculated = new WorkflowCirculated();
+                workflowCirculated.setProcessId(task.getProcessInstanceId());
+                workflowCirculated.setCreateTime(DateUtil.toLocalDateTime(task.getCreateTime()));
+                workflowCirculated.setTaskId(task.getId());
+                workflowCirculated.setCurrentProgress(userTaskConfig.getCurrentProgress());
+                workflowCirculated.setTaskName(task.getName());
+                workflowCirculated.setIsRead(YesOrNoEnum.NO.getCode());
+                workflowCirculated.setSchemaId(MapUtil.getLong(variableMaps, WorkflowConstant.PROCESS_SCHEMA_ID_KEY));
+                workflowCirculated.setCirculatedUserId(userId);
+                workflowCirculated.setStartUserId(MapUtil.getLong(variableMaps, WorkflowConstant.PROCESS_START_USER_ID_KEY));
+                workflowCirculated.setSerialNumber(MapUtil.getLong(variableMaps, WorkflowConstant.PROCESS_SERIAL_NUMBER_KEY));
+
+                circulatedList.add(workflowCirculated);
+            }
+            circulatedService.saveBatch(circulatedList);
+            //[操作人名称] 添加了传阅人[添加传人名称],当前传阅人[所有传问人名称]
+            if (StrUtil.isNotBlank(circulatedName)) {
+                circulateMessage = "【" + user.getName() + "】添加了传阅人【" + circulatedName + "】,当前传阅人【" + circulatedName + "】";
+            }
+//            String message = "【" + user.getName() + "】添加了传阅人【" + circulatedName + ",当前传阅人【" + circulatedName + "】";
+//            addProcessRecord(task, schemaId, message);
+        } else {
+            List<WorkflowCirculated> newList = new ArrayList<>();
+            for (Long userId : appendUserTaskCirculated) {
+                WorkflowCirculated workflowCirculated = BeanUtil.toBean(circulatedList.get(0), WorkflowCirculated.class);
+                workflowCirculated.setCirculatedUserId(userId);
+                workflowCirculated.setId(null);
+                newList.add(workflowCirculated);
+            }
+            circulatedService.saveBatch(newList);
+            //[操作人名称] 添加了传阅人[添加传人名称],当前传阅人[所有传问人名称] = 需要追加的传阅人 + 原本的传阅人
+            for (WorkflowCirculated workflowCirculated : circulatedList) {
+                //将原本的传阅人加入到需要追加的传阅人中
+                appendUserTaskCirculated.add(workflowCirculated.getCirculatedUserId());
+            }
+            String addCirculatedName = getAllUserNamesByIds(appendUserTaskCirculated); //增加后的当前传阅人
+//            String message = "【" + user.getName() + "】添加了传阅人【" + circulatedName + "】,当前传阅人【" + addCirculatedName + "】";
+//            addProcessRecord(task, schemaId, message);
+            if (StrUtil.isNotBlank(addCirculatedName)) {
+                circulateMessage = "【" + user.getName() + "】添加了传阅人【" + circulatedName + "】,当前传阅人【" + addCirculatedName + "】";
+            }
+        }
+        return circulateMessage;
+    }
+
+    /**
+     * 根据用户id获取对应的用户名,并进行拼接输出
+     *
+     * @param allUserIds 用户ids
+     * @return 用户名(张三、李四)
+     */
+    private String getAllUserNamesByIds(List<Long> allUserIds) {
+        String allDelegateUserNames = "";
+        List<User> userList = redisUtil.get(GlobalConstant.USER_CACHE_KEY, new TypeReference<List<User>>() {
+        });
+        //如果缓存中不存在用户信息,就直接去数据库查询
+        if (userList.size() == 0) {
+            userList = userService.list();
+            redisUtil.set(GlobalConstant.USER_CACHE_KEY, userList);
+        }
+        if (allUserIds.size() > 0) {
+            //获取用户id对应的用户名
+            List<String> allUserName = userList.stream().filter(u -> allUserIds.contains(u.getId())).map(User::getName).collect(Collectors.toList());
+            if (allUserName.size() > 0) {
+                allDelegateUserNames = StrUtil.join("、", allUserName);
+            }
+        }
+        return allDelegateUserNames;
+    }
+
+    /**
+     * 新增工作流程信息数据
+     *
+     * @param userTaskConfig   用户任务配置信息
+     * @param nextTaskNameList 下一个节点的名称集合
+     * @param user             当前用户的对象
+     * @param record           工作流程信息的对象
+     * @param oldTaskName      前一个节点的名称
+     * @param buttonName       按钮名称
+     */
+    private void addWorkflowRecord(UserTaskConfig userTaskConfig, List<String> nextTaskNameList, User user, WorkflowRecord record, String oldTaskName, String buttonName, String approvedContent, Task task, Object resultName) {
+        //单实例
+        if (userTaskConfig.getCountersignConfig().getMultipleInstancesType() == WorkflowMultiInstanceType.NONE.getCode()) {
+            //用户节点到结束节点或者脚本节点,点击按钮时,也需要设置流程信息
+            if (nextTaskNameList.size() == 0 && !buttonName.equals("")) {
+                String message = "【" + user.getName() + "】【" + buttonName + "】审批,审批意见为:“【" + approvedContent + "】“";
+                record.setMessage(message);
+            }
+            //单流向
+            if (nextTaskNameList.size() == 1) {
+                String message = "【" + user.getName() + "】【" + buttonName + "】审批,审批意见为:“【" + approvedContent + "】”,由【" + oldTaskName + "】 流转到【" + nextTaskNameList.get(0) + "】";
+                record.setMessage(message);
+            }//多流向
+            if (nextTaskNameList.size() > 1) {
+                String message = "【" + user.getName() + "】【" + buttonName + "】审批,审批意见为:“【" + approvedContent + "】”,由【" + oldTaskName + "】 流转到【" + nextTaskNameList.get(0) + "】";
+                for (int i = 1; i < nextTaskNameList.size(); i++) {
+                    message = message + "、【" + nextTaskNameList.get(i) + "】";
+                }
+                record.setMessage(message);
+            }
+        }
+        //多实例,判断是不是会签流程,以及会签流程的状态
+        else {
+            //判断是否达到完成条件
+            List<HistoricVariableInstance> list = historyService.createHistoricVariableInstanceQuery().processInstanceIdIn(task.getProcessInstanceId()).list();
+            Boolean getCompleteConditional = isGetCompleteConditional(userTaskConfig, list);
+
+            //审批但未达到完成条件;审批信息:[会签][用户名] [审批按钮名称]审批,审批意见为:“[审批意见]”。
+            if (getCompleteConditional) {
+                //获取当前节点是否完成会签或者会签失败
+                if (ObjectUtil.isNotEmpty(resultName)) { //resultName只能从这个节点拿,不然会签节点后直接结束流程,就会拿不到流程变量信息
+                    Boolean isSuccess = new Boolean(resultName.toString());
+                    //审批达到完成条件,完成会签;审批信息:[会签][用户名] [审按名称]审批,审批见为:[审批意见]”,达到会签完成条件,由[上一节点名称]流转到下,多流向的情况则由[上一节点名称] 流转到[多流向节点名称]。
+                    if (isSuccess) {
+                        //用户节点到结束节点或者脚本节点,点击按钮时,也需要设置流程信息
+                        if (nextTaskNameList.size() == 0 && !buttonName.equals("")) {
+                            String message = "【会签】【" + user.getName() + "】【" + buttonName + "】审批,审批意见为:“【" + approvedContent + "】“,达到会签完成条件";
+                            record.setMessage(message);
+                        }
+                        //单流向
+                        if (nextTaskNameList.size() == 1) {
+                            String message = "【会签】【" + user.getName() + "】【" + buttonName + "】审批,审批意见为:“【" + approvedContent + "】”,达到会签完成条件,由【" + oldTaskName + "】 流转到【" + nextTaskNameList.get(0) + "】";
+                            record.setMessage(message);
+                        }//多流向
+                        if (nextTaskNameList.size() > 1) {
+                            String message = "【会签】【" + user.getName() + "】【" + buttonName + "】审批,审批意见为:“【" + approvedContent + "】”,达到会签完成条件,由【" + oldTaskName + "】 流转到【" + nextTaskNameList.get(0) + "】";
+                            for (int i = 1; i < nextTaskNameList.size(); i++) {
+                                message = message + "、【" + nextTaskNameList.get(i) + "】";
+                            }
+                            record.setMessage(message);
+                        }
+                    }
+                    //审批达到完成条件,会签失败;例如:审批信息:[会签][用户名][审按名称]审批,审批意见为:“[审批意见]”,未达到会签完成条件,由[管理层审批]流转到(部门审批]
+                    if (buttonName.equals(WorkflowApproveType.DISAGREE.getValue())) {
+                        //用户节点到结束节点或者脚本节点,点击按钮时,也需要设置流程信息
+                        if (nextTaskNameList.size() == 0 && !buttonName.equals("")) {
+                            String message = "【会签】【" + user.getName() + "】【" + buttonName + "】审批,审批意见为:“【" + approvedContent + "】“,未达到会签完成条件";
+                            record.setMessage(message);
+                        }
+                        //单流向
+                        if (nextTaskNameList.size() == 1) {
+                            String message = "【会签】【" + user.getName() + "】【" + buttonName + "】审批,审批意见为:“【" + approvedContent + "】”,未达到会签完成条件,由【" + oldTaskName + "】 流转到【" + nextTaskNameList.get(0) + "】";
+                            record.setMessage(message);
+                        }//多流向
+                        if (nextTaskNameList.size() > 1) {
+                            String message = "【会签】【" + user.getName() + "】【" + buttonName + "】审批,审批意见为:“【" + approvedContent + "】”,未达到会签完成条件,由【" + oldTaskName + "】 流转到【" + nextTaskNameList.get(0) + "】";
+                            for (int i = 1; i < nextTaskNameList.size(); i++) {
+                                message = message + "、【" + nextTaskNameList.get(i) + "】";
+                            }
+                            record.setMessage(message);
+                        }
+                    }
+                }
+            } else {
+                //审批但未达到完成条件;审批信息:[会签][用户名] [审批按钮名称]审批,审批意见为:“[审批意见]”。
+                String message = "【会签】【" + user.getName() + "】【" + buttonName + "】审批,审批意见为:“【" + approvedContent + "】“";
+                record.setMessage(message);
+            }
+        }
+        workflowRecordMapper.insert(record);
+    }
+
+    /**
+     * 判断多实例是否达到完成条件
+     *
+     * @param userTaskConfig
+     * @param list
+     * @return
+     */
+    private Boolean isGetCompleteConditional(UserTaskConfig userTaskConfig, List<HistoricVariableInstance> list) {
+        int nrOfInstances = 0;
+        int nrOfCompletedInstances = 0;
+        int nrOfActiviteInstances = 0;
+        for (HistoricVariableInstance historicVariableInstance : list) {
+            //nrOfInstances:总共的实例数;
+            if (historicVariableInstance.getName().equals(WorkflowConstant.MULTI_INSTANCE_VAR_KEY)) {
+                nrOfInstances = Integer.parseInt(String.valueOf(historicVariableInstance.getValue()));
+            }
+            //nrOfCompletedInstances:已完成的实例数;
+            if (historicVariableInstance.getName().equals(WorkflowConstant.MULTI_COMPLETED_INSTANCE_VAR_KEY)) {
+                nrOfCompletedInstances = Integer.parseInt(String.valueOf(historicVariableInstance.getValue()));
+            }
+            //nrOfActiviteInstances;当前活动的实例数量,即还没有完成的实例数量
+            if (historicVariableInstance.getName().equals(WorkflowConstant.MULTI_ACTIVE_INSTANCE_VAR_KEY)) {
+                nrOfActiviteInstances = Integer.parseInt(String.valueOf(historicVariableInstance.getValue()));
+            }
+        }
+        //获取流程参数中的完成条件,完成条件 0 全部  1 单个 2百分比
+        if (userTaskConfig.getCountersignConfig().getFinishType() == 0) {
+            if (nrOfActiviteInstances == 0) {
+                return true;
+            }
+        } else if (userTaskConfig.getCountersignConfig().getFinishType() == 1) {
+            if (nrOfCompletedInstances > 0) {
+                return true;
+            }
+        } else if (userTaskConfig.getCountersignConfig().getFinishType() == 2) {
+            //判断完成百分比是否达到
+            if ((nrOfCompletedInstances / nrOfInstances) * 100 > userTaskConfig.getCountersignConfig().getPercentage()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public Boolean dealTimeoutTask(Integer handleType, String taskId) {
+        //根据taskid  获取任务信息
+        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
+
+        if (task == null) {
+            throw new MyException("找不到此任务!");
+        }
+
+        //获取当前任务变量中的  schemaId
+        Long schemaId = Convert.toLong(taskService.getVariable(task.getId(), WorkflowConstant.PROCESS_SCHEMA_ID_KEY));
+
+        //排除xml 查出数据
+        WorkflowSchema workflowSchema = workflowSchemaMapper.selectOne(Wrappers.lambdaQuery(WorkflowSchema.class).eq(WorkflowSchema::getId, schemaId).select(x -> !x.getProperty().startsWith(DB_FIELD_XML_PREFIX)));
+
+        //获取到整个流程模板的配置
+        WorkflowSchemaConfig workflowSchemaConfig = JSONUtil.toBean(workflowSchema.getJsonContent(), WorkflowSchemaConfig.class);
+        //找到当前用户任务节点的配置信息
+        Optional<Map<String, Object>> userTaskMapOptional = workflowSchemaConfig.getChildNodeConfig().stream().filter(x -> x.containsValue(task.getTaskDefinitionKey())).findFirst();
+        //判断是否找得到此任务节点 没有则报错
+        if (!userTaskMapOptional.isPresent()) {
+            throw new MyException("【任务id :" + task.getId() + "】 用户任务节点配置有误,请联系管理员!");
+        }
+
+        //查出所有表单数据
+        VariableMap variableMap = Variables.createVariables();
+
+        List<LaunchAndApproveVo> result = new ArrayList<>();
+
+        if (handleType == 1) {//自动驳回
+            //获取到当前活动的实例
+            ActivityInstance activityInstance = runtimeService.getActivityInstance(task.getProcessInstanceId());
+
+            //获取所有已办任务节点
+            List<HistoricActivityInstance> resultList = historyService
+                    .createHistoricActivityInstanceQuery()
+                    .processInstanceId(task.getProcessInstanceId())
+                    .activityType("userTask")
+                    .finished()
+                    .orderByHistoricActivityInstanceEndTime()
+                    .asc()
+                    .list();
+
+            if (null == resultList || resultList.size() == 0) {
+                throw new MyException("当前任务之前不存在用户任务无法驳回!");
+            }
+            //得到第一个任务节点的id
+            HistoricActivityInstance historicActivityInstance = resultList.get(0);
+            String startActId = historicActivityInstance.getActivityId();
+            if (startActId.equals(task.getTaskDefinitionKey())) {
+                throw new MyException("开始节点无法驳回!");
+            }
+
+            //得到上一个任务节点的ActivityId和待办人
+            Map<String, String> lastNode = getLastNode(resultList, task.getTaskDefinitionKey());
+            if (null == lastNode) {
+                throw new MyException("回退节点异常!");
+            }
+            String toActId = lastNode.get("toActId");
+            String assignee = lastNode.get("assignee");
+            //设置流程中的可变参数
+            Map<String, Object> taskVariable = new HashMap<>(2);
+            taskVariable.put("user", assignee);
+            taskService.createComment(task.getId(), task.getProcessInstanceId(), "驳回原因:" + "自动驳回");
+
+            //先停止当前活动示例  然后撤回流程到上个节点
+            runtimeService.createProcessInstanceModification(task.getProcessInstanceId())
+                    .cancelActivityInstance(getInstanceIdForActivity(activityInstance, task.getTaskDefinitionKey()))//关闭相关任务
+                    .setAnnotation("系统" + "】 自动驳回 【任务:" + task.getId() + "】")
+                    .startBeforeActivity(toActId) //上一个节点
+                    .setVariables(taskVariable)//流程的可变参数赋值
+                    .execute();
+
+            Optional<Map<String, Object>> rejectNodeMap = workflowSchemaConfig.getChildNodeConfig().stream().filter(x -> x.containsValue(toActId)).findFirst();
+
+            rejectNodeMap.ifPresent(node -> {
+                //将map 转为 java类
+                UserTaskConfig rejectUserTaskConfig = Convert.convert(UserTaskConfig.class, node);
+
+                //新增流程发起流程记录
+                WorkflowRecord record = new WorkflowRecord();
+                record.setNodeId(task.getId());
+                record.setNodeName(task.getName());
+                record.setNodeType(WorkflowConstant.USER_TASK_TYPE_NAME);
+                record.setProcessId(task.getProcessInstanceId());
+                record.setSchemaId(schemaId);
+                record.setNodeMultiType(WorkflowMultiInstanceType.NONE.getCode());
+                record.setRecordTime(LocalDateTime.now().minusSeconds(+1));//时间设置提前1秒钟,好排序
+
+//                    record.setMessage("【审批人:" + user.getName() + "】 将 【任务:" + task.getName() + "】 驳回到 【任务:" + rejectUserTaskConfig.getName() + "】");
+                record.setMessage("审批信息:由于审批超时,【系统】【自动驳回】审批,审批意见为:“系统自动驳回审批”,由【" + task.getName() + "】 流转到【" + rejectUserTaskConfig.getName() + "】");
+                workflowRecordMapper.insert(record);
+            });
+        } else if (handleType == 2) {//同意
+            //新增流程发起流程记录
+            WorkflowRecord record = new WorkflowRecord();
+            record.setNodeId(task.getId());
+            record.setNodeName(task.getName());
+            record.setNodeType(WorkflowConstant.USER_TASK_TYPE_NAME);
+            record.setProcessId(task.getProcessInstanceId());
+            record.setSchemaId(schemaId);
+            record.setNodeMultiType(WorkflowMultiInstanceType.NONE.getCode());
+            //时间设值必须写在complete上面,防止用户任务节点监听时的流程信息,在次任务前面。
+            record.setRecordTime(LocalDateTime.now());
+            //当前任务的名称
+            String oldTaskName = task.getName();
+
+            taskService.complete(task.getId());
+            List<Task> list = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list();
+            result = isPrevChooseApprove(workflowSchemaConfig, list, variableMap);
+
+            //下一个节点的任务名称集合
+            List<String> nextTaskNameList = list.stream().map(Task::getName).collect(Collectors.toList());
+
+            //如果不需要指定审批人 默认走自动同意规则
+//            invokeAutoAgree(task.getProcessInstanceId(), workflowSchema.getId(), workflowSchemaConfig, list);
+
+            //用户节点到结束节点或者脚本节点,点击按钮时,也需要设置流程信息
+            if (nextTaskNameList.size() == 0) {
+                String message = "审批信息:由于审批超时,【系统】【自动同意】审批,审批意见为:“系统自动同意审批”,由【" + oldTaskName + "】 流转到【" + "结束节点" + "】";
+                record.setMessage(message);
+            }
+            //单流向
+            if (nextTaskNameList.size() == 1) {
+                String message = "审批信息:由于审批超时,【系统】【自动同意】审批,审批意见为:“系统自动同意审批”,由【" + oldTaskName + "】 流转到【" + nextTaskNameList.get(0) + "】";
+                record.setMessage(message);
+            }//多流向
+            if (nextTaskNameList.size() > 1) {
+                String message = "审批信息:由于审批超时,【系统】【自动同意】审批,审批意见为:“系统自动同意审批”,由【" + oldTaskName + "】 流转到【" + nextTaskNameList.get(0) + "】";
+                for (int i = 1; i < nextTaskNameList.size(); i++) {
+                    message = message + "、【" + nextTaskNameList.get(i) + "】";
+                }
+                record.setMessage(message);
+            }
+
+            workflowRecordMapper.insert(record);
+        }
+        return true;
+    }
+
+    /**
+     * 获取上一节点信息
+     * 分两种情况:
+     * 1、当前节点不在历史节点里
+     * 2、当前节点在历史节点里
+     * 比如,resultList={1,2,3}
+     * (1)当前节点是4,表示3是完成节点,4驳回需要回退到3
+     * (2)当前节点是2,表示3是驳回节点,3驳回到当前2节点,2驳回需要回退到1
+     * 其他驳回过的情况也都包含在情况2中。
+     *
+     * @param resultList        历史节点列表
+     * @param currentActivityId 当前待办节点ActivityId
+     * @return 返回值:上一节点的ActivityId和待办人(toActId, assignee)
+     */
+    private static Map<String, String> getLastNode(List<HistoricActivityInstance> resultList, String currentActivityId) {
+        Map<String, String> backNode = new HashMap<>();
+        //新建一个有序不重复集合
+        LinkedHashMap<String, String> linkedHashMap = new LinkedHashMap();
+        for (HistoricActivityInstance hai : resultList) {
+            linkedHashMap.put(hai.getActivityId(), hai.getAssignee());
+        }
+        //分两种情况:当前节点在不在历史节点里面,当前节点在历史节点里
+        //情况1、当前节点不在历史节点里
+        int originSize = resultList.size();
+        int duplicateRemovalSize = linkedHashMap.size();
+        //判断历史节点中是否有重复节点
+        //if(originSize == duplicateRemovalSize){
+        boolean flag = false;
+        for (Map.Entry entry : linkedHashMap.entrySet()) {
+            if (currentActivityId.equals(entry.getKey())) {
+                flag = true;
+                break;
+            }
+        }
+        if (!flag) {
+            //当前节点不在历史节点里:最后一个节点是完成节点
+            HistoricActivityInstance historicActivityInstance = resultList.get(originSize - 1);
+            backNode.put("toActId", historicActivityInstance.getActivityId());
+            backNode.put("assignee", historicActivityInstance.getAssignee());
+            return backNode;
+        }
+        //情况2、当前节点在历史节点里(已回退过的)
+        return currentNodeInHis(linkedHashMap, currentActivityId);
+    }
+
+    private String getInstanceIdForActivity(ActivityInstance activityInstance, String activityId) {
+        ActivityInstance instance = getChildInstanceForActivity(activityInstance, activityId);
+        if (instance != null) {
+            return instance.getId();
+        }
+        return null;
+    }
+
+    private ActivityInstance getChildInstanceForActivity(ActivityInstance activityInstance, String activityId) {
+        if (activityId.equals(activityInstance.getActivityId())) {
+            return activityInstance;
+        }
+        for (ActivityInstance childInstance : activityInstance.getChildActivityInstances()) {
+            ActivityInstance instance = getChildInstanceForActivity(childInstance, activityId);
+            if (instance != null) {
+                return instance;
+            }
+        }
+        return null;
+    }
+
+    private static Map<String, String> currentNodeInHis(LinkedHashMap<String, String> linkedHashMap, String currentActivityId) {
+        //情况2、当前节点在历史节点里(已回退过的)
+        Map<String, String> backNode = new HashMap<>();
+        ListIterator<Map.Entry<String, String>> li = new ArrayList<>(linkedHashMap.entrySet()).listIterator();
+        //System.out.println("已回退过的");
+        while (li.hasNext()) {
+            Map.Entry<String, String> entry = li.next();
+            if (currentActivityId.equals(entry.getKey())) {
+                li.previous();
+                Map.Entry<String, String> previousEntry = li.previous();
+                backNode.put("toActId", previousEntry.getKey());
+                backNode.put("assignee", previousEntry.getValue());
+                return backNode;
+            }
+        }
+        return null;
+    }
+}

+ 14 - 4
src/main/resources/application-dev.yml

@@ -5,10 +5,20 @@ spring:
   datasource:
     type: com.alibaba.druid.pool.DruidDataSource
     driver-class-name: com.mysql.cj.jdbc.Driver
-    url: jdbc:mysql://10.150.10.139:3306/tl?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&autoReconnect=true&failOverReadOnly=false
+    url: jdbc:mysql://10.150.10.139:3306/tl?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&autoReconnect=true&failOverReadOnly=false&testWhileIdle=true
     username: root
     password: Zwr~-f6H,u6QE^]C-AD_
-#    dynamic:
+    druid:
+      # 验证连接的有效性
+      test-while-idle: true
+      # 获取连接时候验证,会影响性能
+      test-on-borrow: true
+      # 空闲连接回收的时间间隔,与test-while-idle一起使用,设置5分钟
+      time-between-eviction-runs-millis: 300000
+      # 连接池空闲连接的有效时间 ,设置30分钟
+      min-evictable-idle-time-millis: 1800000
+      max-active: 200
+  #    dynamic:
 #      primary: master
 #      datasource:
 #        master:
@@ -18,7 +28,7 @@ spring:
 #          password: Zwr~-f6H,u6QE^]C-AD_
 
   redis:
-    database: 11
+    database: 10
     host: 10.150.10.139
     port: 6379
     password: wa3re~86Hu&ifniyM   # 密码(默认为空)
@@ -63,7 +73,7 @@ xjrsoft:
   common:
     druid-account: admin # druid 监控账户
     druid-password: admin # druid 监控密码
-    default-password: "Aa123456." #默认密码(用户重置密码后为该密码)
+    default-password: "cqtlzjzx2023" #默认密码(用户重置密码后为该密码)
     domain-api: http://10.150.10.139:8888/api #api域名地址
 #    domain-app: https://yxh-web.ngrok.yingcaibx.com/# #app域名地址
     #domain-app: http://172.19.17.106:5173/app/# #app域名地址

+ 1 - 0
src/main/resources/application.yml

@@ -119,6 +119,7 @@ mybatis-plus:
       logic-delete-value: 1
       logic-not-delete-value: 0
     banner: false
+    enable-sql-runner: true
   #原生配置
   configuration:
     map-underscore-to-camel-case: true

+ 5 - 20
src/main/resources/mapper/room/RoomBedMapper.xml

@@ -100,12 +100,7 @@
         WHERE c1.delete_mark = 0 AND c2.delete_mark = 0
         AND c3.code = 'FB3002' AND c2.class_id = t1.id
         <if test="dto.gender != null">
-            <if test="dto.gender == 'SB10001'">
-                and c4.gender = 1
-            </if>
-            <if test="dto.gender == 'SB10002'">
-                and c4.gender = 2
-            </if>
+            and c4.gender = #{dto.gender}
         </if>
         ) AS need_count,
         (
@@ -115,12 +110,7 @@
         WHERE a1.delete_mark = 0 AND a2.delete_mark = 0
         AND a2.class_id = t1.id
         <if test="dto.gender != null">
-            <if test="dto.gender == 'SB10001'">
-                and c4.gender = 1
-            </if>
-            <if test="dto.gender == 'SB10002'">
-                and c4.gender = 2
-            </if>
+            and c4.gender = #{dto.gender}
         </if>
         ) AS distribute_count FROM base_class t1
         LEFT JOIN base_grade t2 ON t1.grade_id = t2.id
@@ -134,12 +124,7 @@
         WHERE c1.delete_mark = 0 AND c2.delete_mark = 0
         AND c3.code = 'FB3002' AND c2.class_id = t1.id
         <if test="dto.gender != null">
-            <if test="dto.gender == 'SB10001'">
-                and c4.gender = 1
-            </if>
-            <if test="dto.gender == 'SB10002'">
-                and c4.gender = 2
-            </if>
+            and c4.gender = #{dto.gender}
         </if>
         ) >
         (
@@ -179,7 +164,7 @@
         LEFT JOIN xjr_user t3 ON t2.user_id = t3.id
         WHERE t1.delete_mark = 0
         AND t2.delete_mark = 0 AND t3.delete_mark = 0
-        AND t3.gender = 1
+        AND t3.gender = 'SB10001'
         AND t2.stduy_status = 'FB3002' GROUP BY t1.id
     </select>
     <!-- 需要安排的女生总人数 -->
@@ -189,7 +174,7 @@
         LEFT JOIN xjr_user t3 ON t2.user_id = t3.id
         WHERE t1.delete_mark = 0
         AND t2.delete_mark = 0 AND t3.delete_mark = 0
-        AND t3.gender = 2
+        AND t3.gender = 'SB10002'
         AND t2.stduy_status = 'FB3002' GROUP BY t1.id
     </select>
     <!-- 已分配的总人数 -->

+ 97 - 0
src/test/java/com/xjrsoft/xjrsoftboot/SqlRunnerAdapterTest.java

@@ -0,0 +1,97 @@
+package com.xjrsoft.xjrsoftboot;
+
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.db.Entity;
+import com.xjrsoft.XjrSoftApplication;
+import com.xjrsoft.common.mybatis.SqlRunnerAdapter;
+import org.junit.jupiter.api.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.transaction.annotation.Transactional;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = XjrSoftApplication.class)
+public class SqlRunnerAdapterTest {
+
+    @Transactional
+    @Test
+    public void DynamicUpdateTest() {
+        String tableName = "room";
+        Entity params = Entity.create(tableName);
+        params.set("gender","SB10003");
+        params.set("bed_count",10);
+
+
+        Entity where = Entity.create(tableName);
+        where.set("id","1745648843609927682");
+        where.set("create_user_id","14954812448325");
+
+        Boolean result = SqlRunnerAdapter.db().dynamicUpdate(tableName,params,where);
+        System.out.println(result);
+    }
+
+    @Transactional
+    @Test
+    public void DynamicInsertTest() {
+        String tableName = "official_document_received";
+        long keyValue = IdUtil.getSnowflakeNextId();
+        Entity params = Entity.create(tableName);
+        params.set("communication_number","12312");
+        params.set("emergency_level","emergency_level2");
+        params.set("document_level","document_level1");
+        params.set("communication_org","asdfasd");
+        params.set("received_date","2024-02-26");
+        params.set("checkout_time","2024-02-26 00:06:00");
+        params.set("file_id","1761947003676405762");
+        params.set("received_title","发生的发生的newnewnewnnewnewnewewewewe");
+        params.set("received_type","rt_administrative");
+        params.set("received_number","123123");
+        params.set("id",keyValue);
+        params.set("create_user_id","1000000000000000000");
+        params.set("create_date","2024-02-27 17:43:59.140274");
+        params.set("delete_mark","0");
+        params.set("enabled_mark","1");
+
+        Boolean result = SqlRunnerAdapter.db().dynamicInsert(tableName,params);
+        System.out.println(result);
+    }
+
+    @Transactional
+    @Test
+    public void DynamicDeleteTest() {
+        String tableName = "room";
+        Entity where = Entity.create(tableName);
+        where.set("id","1745648843609927682");
+        where.set("create_user_id","14954812448325");
+
+        Boolean result = SqlRunnerAdapter.db().dynamicDelete(tableName,where);
+        System.out.println(result);
+    }
+
+    @Transactional
+    @Test
+    public void DynamicTest() throws Exception {
+        String tableName = "room";
+        Entity where = Entity.create(tableName);
+        where.set("id","1745648844138409985");
+        where.set("create_user_id","14954812448325");
+
+        Boolean result = SqlRunnerAdapter.db().dynamicDelete(tableName,where);
+        System.out.println(result);
+
+        Entity params = Entity.create(tableName);
+        params.set("gender","SB10003");
+        params.set("bed_count",10);
+
+
+        Entity where2 = Entity.create(tableName);
+        where.set("id","1745648843890946050");
+        where.set("create_user_id","14954812448325");
+
+        Boolean result2 = SqlRunnerAdapter.db().dynamicUpdate(tableName,params,where2);
+        System.out.println(result2);
+
+        throw new Exception("错误回滚");
+    }
+}

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است