Zn 1 rok temu
rodzic
commit
ba1adedc8b
24 zmienionych plików z 1645 dodań i 102 usunięć
  1. 113 0
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysBpmNodeScriptController.java
  2. 12 1
      ruoyi-common/src/main/java/com/ruoyi/common/core/page/PageDomain.java
  3. 11 7
      ruoyi-common/src/main/java/com/ruoyi/common/core/page/TableSupport.java
  4. 11 12
      ruoyi-common/src/main/java/com/ruoyi/common/utils/PageUtils.java
  5. 132 0
      ruoyi-system/src/main/java/com/ruoyi/system/domain/SysBpmNodeScript.java
  6. 61 0
      ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysBpmNodeScriptMapper.java
  7. 61 0
      ruoyi-system/src/main/java/com/ruoyi/system/service/ISysBpmNodeScriptService.java
  8. 101 0
      ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysBpmNodeScriptServiceImpl.java
  9. 95 0
      ruoyi-system/src/main/resources/mapper/system/SysBpmNodeScriptMapper.xml
  10. 1 0
      ruoyi-ui/package.json
  11. 46 2
      ruoyi-ui/src/api/bpmprocess/process.js
  12. 1 1
      ruoyi-ui/src/main.js
  13. 5 0
      ruoyi-ui/src/store/modules/user.js
  14. 371 0
      ruoyi-ui/src/views/bpmprocess/scriptManage.vue
  15. 2 2
      ruoyi-ui/src/views/system/bpmnPro/components/Panel/components/ElementExecuteUser.vue
  16. 193 0
      ruoyi-ui/src/views/system/bpmnPro/components/Panel/components/ElementUnusualTasks.vue
  17. 5 2
      ruoyi-ui/src/views/system/bpmnPro/components/Panel/index.vue
  18. 12 5
      ruoyi-ui/src/views/system/bpmnPro/components/Toolbar/tools/Save.vue
  19. 74 10
      ruoyi-ui/src/views/system/bpmnPro/components/bo-utils/getNodeMsg.js
  20. 74 1
      ruoyi-ui/src/views/system/bpmnPro/components/bo-utils/myFieldUtil.js
  21. 67 0
      ruoyi-ui/src/views/system/bpmnPro/components/moddle-extensions/activiti.json
  22. 65 2
      ruoyi-ui/src/views/system/bpmnPro/components/moddle-extensions/camunda.json
  23. 64 1
      ruoyi-ui/src/views/system/bpmnPro/components/moddle-extensions/flowable.json
  24. 68 56
      ruoyi-ui/src/views/tablelist/commonTable/queryfrom.vue

+ 113 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysBpmNodeScriptController.java

@@ -0,0 +1,113 @@
+package com.ruoyi.web.controller.system;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.system.domain.SysBpmNodeScript;
+import com.ruoyi.system.service.ISysBpmNodeScriptService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 流程节点脚本Controller
+ *
+ * @author ruoyi
+ * @date 2023-10-26
+ */
+@RestController
+@RequestMapping("/system/script")
+@Api(value = "/system/script")
+public class SysBpmNodeScriptController extends BaseController
+{
+    @Autowired
+    private ISysBpmNodeScriptService sysBpmNodeScriptService;
+
+    /**
+     * 查询流程节点脚本列表
+     */
+//    @PreAuthorize("@ss.hasPermi('system:script:list')")
+    @GetMapping("/list")
+    @ApiOperation(value = "查询流程节点脚本列表")
+    public TableDataInfo list(SysBpmNodeScript sysBpmNodeScript)
+    {
+        startPage();
+        List<SysBpmNodeScript> list = sysBpmNodeScriptService.selectSysBpmNodeScriptList(sysBpmNodeScript);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出流程节点脚本列表
+     */
+//    @PreAuthorize("@ss.hasPermi('system:script:export')")
+    @Log(title = "流程节点脚本", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    @ApiOperation(value = "导出流程节点脚本列表")
+    public void export(HttpServletResponse response, SysBpmNodeScript sysBpmNodeScript)
+    {
+        List<SysBpmNodeScript> list = sysBpmNodeScriptService.selectSysBpmNodeScriptList(sysBpmNodeScript);
+        ExcelUtil<SysBpmNodeScript> util = new ExcelUtil<SysBpmNodeScript>(SysBpmNodeScript.class);
+        util.exportExcel(response, list, "流程节点脚本数据");
+    }
+
+    /**
+     * 获取流程节点脚本详细信息
+     */
+//    @PreAuthorize("@ss.hasPermi('system:script:query')")
+    @GetMapping(value = "/{id}")
+    @ApiOperation(value = "获取流程节点脚本详细信息")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return success(sysBpmNodeScriptService.selectSysBpmNodeScriptById(id));
+    }
+
+    /**
+     * 新增流程节点脚本
+     */
+//    @PreAuthorize("@ss.hasPermi('system:script:add')")
+    @Log(title = "流程节点脚本", businessType = BusinessType.INSERT)
+    @PostMapping
+    @ApiOperation(value = "新增流程节点脚本")
+    public AjaxResult add(@RequestBody SysBpmNodeScript sysBpmNodeScript)
+    {
+        return toAjax(sysBpmNodeScriptService.insertSysBpmNodeScript(sysBpmNodeScript));
+    }
+
+    /**
+     * 修改流程节点脚本
+     */
+//    @PreAuthorize("@ss.hasPermi('system:script:edit')")
+    @Log(title = "流程节点脚本", businessType = BusinessType.UPDATE)
+    @PutMapping
+    @ApiOperation(value = "修改流程节点脚本")
+    public AjaxResult edit(@RequestBody SysBpmNodeScript sysBpmNodeScript)
+    {
+        return toAjax(sysBpmNodeScriptService.updateSysBpmNodeScript(sysBpmNodeScript));
+    }
+
+    /**
+     * 删除流程节点脚本
+     */
+//    @PreAuthorize("@ss.hasPermi('system:script:remove')")
+    @Log(title = "流程节点脚本", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    @ApiOperation(value = "删除流程节点脚本")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(sysBpmNodeScriptService.deleteSysBpmNodeScriptByIds(ids));
+    }
+}

+ 12 - 1
ruoyi-common/src/main/java/com/ruoyi/common/core/page/PageDomain.java

@@ -4,7 +4,7 @@ import com.ruoyi.common.utils.StringUtils;
 
 /**
  * 分页数据
- * 
+ *
  * @author ruoyi
  */
 public class PageDomain
@@ -24,6 +24,9 @@ public class PageDomain
     /** 分页参数合理化 */
     private Boolean reasonable = true;
 
+    /** 是否进行分页操作 */
+    private Boolean isEnablePaging = true;
+
     public String getOrderBy()
     {
         if (StringUtils.isEmpty(orderByColumn))
@@ -98,4 +101,12 @@ public class PageDomain
     {
         this.reasonable = reasonable;
     }
+
+    public Boolean isEnablePaging() {
+        return isEnablePaging;
+    }
+
+    public void setIsEnablePaging(Boolean enablePaging) {
+        isEnablePaging = enablePaging;
+    }
 }

+ 11 - 7
ruoyi-common/src/main/java/com/ruoyi/common/core/page/TableSupport.java

@@ -1,15 +1,15 @@
 package com.ruoyi.common.core.page;
 
 import com.ruoyi.common.core.text.Convert;
+import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.common.utils.ServletUtils;
 
 /**
  * 表格数据处理
- * 
+ *
  * @author ruoyi
  */
-public class TableSupport
-{
+public class TableSupport {
     /**
      * 当前记录起始索引
      */
@@ -35,22 +35,26 @@ public class TableSupport
      */
     public static final String REASONABLE = "reasonable";
 
+    /**
+     * 是否进行分页操作
+     */
+    public static final String ISENABLEPAGING = "isEnablePaging";
+
     /**
      * 封装分页对象
      */
-    public static PageDomain getPageDomain()
-    {
+    public static PageDomain getPageDomain() {
         PageDomain pageDomain = new PageDomain();
         pageDomain.setPageNum(Convert.toInt(ServletUtils.getParameter(PAGE_NUM), 1));
         pageDomain.setPageSize(Convert.toInt(ServletUtils.getParameter(PAGE_SIZE), 10));
         pageDomain.setOrderByColumn(ServletUtils.getParameter(ORDER_BY_COLUMN));
         pageDomain.setIsAsc(ServletUtils.getParameter(IS_ASC));
         pageDomain.setReasonable(ServletUtils.getParameterToBool(REASONABLE));
+        pageDomain.setIsEnablePaging(ServletUtils.getParameterToBool(ISENABLEPAGING));
         return pageDomain;
     }
 
-    public static PageDomain buildPageRequest()
-    {
+    public static PageDomain buildPageRequest() {
         return getPageDomain();
     }
 }

+ 11 - 12
ruoyi-common/src/main/java/com/ruoyi/common/utils/PageUtils.java

@@ -7,29 +7,28 @@ import com.ruoyi.common.utils.sql.SqlUtil;
 
 /**
  * 分页工具类
- * 
+ *
  * @author ruoyi
  */
-public class PageUtils extends PageHelper
-{
+public class PageUtils extends PageHelper {
     /**
      * 设置请求分页数据
      */
-    public static void startPage()
-    {
+    public static void startPage() {
         PageDomain pageDomain = TableSupport.buildPageRequest();
-        Integer pageNum = pageDomain.getPageNum();
-        Integer pageSize = pageDomain.getPageSize();
-        String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
-        Boolean reasonable = pageDomain.getReasonable();
-        PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);
+        if (pageDomain.isEnablePaging()) {
+            Integer pageNum = pageDomain.getPageNum();
+            Integer pageSize = pageDomain.getPageSize();
+            String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
+            Boolean reasonable = pageDomain.getReasonable();
+            PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);
+        }
     }
 
     /**
      * 清理分页的线程变量
      */
-    public static void clearPage()
-    {
+    public static void clearPage() {
         PageHelper.clearPage();
     }
 }

+ 132 - 0
ruoyi-system/src/main/java/com/ruoyi/system/domain/SysBpmNodeScript.java

@@ -0,0 +1,132 @@
+package com.ruoyi.system.domain;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/**
+ * 流程节点脚本对象 sys_bpm_node_script
+ * 
+ * @author ruoyi
+ * @date 2023-10-26
+ */
+public class SysBpmNodeScript extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 编号 */
+    private Long id;
+
+    /** 脚本编码 */
+    private String scriptKey;
+
+    /** 脚本方法名称 */
+    private String scriptFunctionName;
+
+    /** 脚本名称 */
+    private String scriptName;
+
+    /** 脚本方法体 */
+    private String scriptFunctionCode;
+
+    /** 脚本类型 */
+    private Long scriptType;
+
+    /** 脚本描述 */
+    private String scriptDescription;
+
+    /** 删除标志(0:否;1:是) */
+    private String delFlag;
+
+    public void setId(Long id) 
+    {
+        this.id = id;
+    }
+
+    public Long getId() 
+    {
+        return id;
+    }
+    public void setScriptKey(String scriptKey) 
+    {
+        this.scriptKey = scriptKey;
+    }
+
+    public String getScriptKey() 
+    {
+        return scriptKey;
+    }
+    public void setScriptFunctionName(String scriptFunctionName) 
+    {
+        this.scriptFunctionName = scriptFunctionName;
+    }
+
+    public String getScriptFunctionName() 
+    {
+        return scriptFunctionName;
+    }
+    public void setScriptName(String scriptName) 
+    {
+        this.scriptName = scriptName;
+    }
+
+    public String getScriptName() 
+    {
+        return scriptName;
+    }
+    public void setScriptFunctionCode(String scriptFunctionCode) 
+    {
+        this.scriptFunctionCode = scriptFunctionCode;
+    }
+
+    public String getScriptFunctionCode() 
+    {
+        return scriptFunctionCode;
+    }
+    public void setScriptType(Long scriptType) 
+    {
+        this.scriptType = scriptType;
+    }
+
+    public Long getScriptType() 
+    {
+        return scriptType;
+    }
+    public void setScriptDescription(String scriptDescription) 
+    {
+        this.scriptDescription = scriptDescription;
+    }
+
+    public String getScriptDescription() 
+    {
+        return scriptDescription;
+    }
+    public void setDelFlag(String delFlag) 
+    {
+        this.delFlag = delFlag;
+    }
+
+    public String getDelFlag() 
+    {
+        return delFlag;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("id", getId())
+            .append("scriptKey", getScriptKey())
+            .append("scriptFunctionName", getScriptFunctionName())
+            .append("scriptName", getScriptName())
+            .append("scriptFunctionCode", getScriptFunctionCode())
+            .append("scriptType", getScriptType())
+            .append("scriptDescription", getScriptDescription())
+            .append("delFlag", getDelFlag())
+            .append("createBy", getCreateBy())
+            .append("createTime", getCreateTime())
+            .append("updateBy", getUpdateBy())
+            .append("updateTime", getUpdateTime())
+            .toString();
+    }
+}

+ 61 - 0
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysBpmNodeScriptMapper.java

@@ -0,0 +1,61 @@
+package com.ruoyi.system.mapper;
+
+import java.util.List;
+import com.ruoyi.system.domain.SysBpmNodeScript;
+
+/**
+ * 流程节点脚本Mapper接口
+ * 
+ * @author ruoyi
+ * @date 2023-10-26
+ */
+public interface SysBpmNodeScriptMapper 
+{
+    /**
+     * 查询流程节点脚本
+     * 
+     * @param id 流程节点脚本主键
+     * @return 流程节点脚本
+     */
+    SysBpmNodeScript selectSysBpmNodeScriptById(Long id);
+
+    /**
+     * 查询流程节点脚本列表
+     * 
+     * @param sysBpmNodeScript 流程节点脚本
+     * @return 流程节点脚本集合
+     */
+    List<SysBpmNodeScript> selectSysBpmNodeScriptList(SysBpmNodeScript sysBpmNodeScript);
+
+    /**
+     * 新增流程节点脚本
+     * 
+     * @param sysBpmNodeScript 流程节点脚本
+     * @return 结果
+     */
+    int insertSysBpmNodeScript(SysBpmNodeScript sysBpmNodeScript);
+
+    /**
+     * 修改流程节点脚本
+     * 
+     * @param sysBpmNodeScript 流程节点脚本
+     * @return 结果
+     */
+    int updateSysBpmNodeScript(SysBpmNodeScript sysBpmNodeScript);
+
+    /**
+     * 删除流程节点脚本
+     * 
+     * @param id 流程节点脚本主键
+     * @return 结果
+     */
+    int deleteSysBpmNodeScriptById(Long id);
+
+    /**
+     * 批量删除流程节点脚本
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteSysBpmNodeScriptByIds(Long[] ids);
+}

+ 61 - 0
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysBpmNodeScriptService.java

@@ -0,0 +1,61 @@
+package com.ruoyi.system.service;
+
+import java.util.List;
+import com.ruoyi.system.domain.SysBpmNodeScript;
+
+/**
+ * 流程节点脚本Service接口
+ * 
+ * @author ruoyi
+ * @date 2023-10-26
+ */
+public interface ISysBpmNodeScriptService 
+{
+    /**
+     * 查询流程节点脚本
+     * 
+     * @param id 流程节点脚本主键
+     * @return 流程节点脚本
+     */
+    SysBpmNodeScript selectSysBpmNodeScriptById(Long id);
+
+    /**
+     * 查询流程节点脚本列表
+     * 
+     * @param sysBpmNodeScript 流程节点脚本
+     * @return 流程节点脚本集合
+     */
+    List<SysBpmNodeScript> selectSysBpmNodeScriptList(SysBpmNodeScript sysBpmNodeScript);
+
+    /**
+     * 新增流程节点脚本
+     * 
+     * @param sysBpmNodeScript 流程节点脚本
+     * @return 结果
+     */
+    int insertSysBpmNodeScript(SysBpmNodeScript sysBpmNodeScript);
+
+    /**
+     * 修改流程节点脚本
+     * 
+     * @param sysBpmNodeScript 流程节点脚本
+     * @return 结果
+     */
+    int updateSysBpmNodeScript(SysBpmNodeScript sysBpmNodeScript);
+
+    /**
+     * 批量删除流程节点脚本
+     * 
+     * @param ids 需要删除的流程节点脚本主键集合
+     * @return 结果
+     */
+    int deleteSysBpmNodeScriptByIds(Long[] ids);
+
+    /**
+     * 删除流程节点脚本信息
+     * 
+     * @param id 流程节点脚本主键
+     * @return 结果
+     */
+    int deleteSysBpmNodeScriptById(Long id);
+}

+ 101 - 0
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysBpmNodeScriptServiceImpl.java

@@ -0,0 +1,101 @@
+package com.ruoyi.system.service.impl;
+
+import java.util.List;
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.SecurityUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.system.mapper.SysBpmNodeScriptMapper;
+import com.ruoyi.system.domain.SysBpmNodeScript;
+import com.ruoyi.system.service.ISysBpmNodeScriptService;
+
+import javax.annotation.Resource;
+
+/**
+ * 流程节点脚本Service业务层处理
+ * 
+ * @author ruoyi
+ * @date 2023-10-26
+ */
+@Service
+public class SysBpmNodeScriptServiceImpl implements ISysBpmNodeScriptService 
+{
+    @Resource
+    private SysBpmNodeScriptMapper sysBpmNodeScriptMapper;
+
+    /**
+     * 查询流程节点脚本
+     * 
+     * @param id 流程节点脚本主键
+     * @return 流程节点脚本
+     */
+    @Override
+    public SysBpmNodeScript selectSysBpmNodeScriptById(Long id)
+    {
+        return sysBpmNodeScriptMapper.selectSysBpmNodeScriptById(id);
+    }
+
+    /**
+     * 查询流程节点脚本列表
+     * 
+     * @param sysBpmNodeScript 流程节点脚本
+     * @return 流程节点脚本
+     */
+    @Override
+    public List<SysBpmNodeScript> selectSysBpmNodeScriptList(SysBpmNodeScript sysBpmNodeScript)
+    {
+        return sysBpmNodeScriptMapper.selectSysBpmNodeScriptList(sysBpmNodeScript);
+    }
+
+    /**
+     * 新增流程节点脚本
+     * 
+     * @param sysBpmNodeScript 流程节点脚本
+     * @return 结果
+     */
+    @Override
+    public int insertSysBpmNodeScript(SysBpmNodeScript sysBpmNodeScript)
+    {
+        sysBpmNodeScript.setCreateTime(DateUtils.getNowDate());
+        sysBpmNodeScript.setCreateBy(SecurityUtils.getUserId().toString());
+        return sysBpmNodeScriptMapper.insertSysBpmNodeScript(sysBpmNodeScript);
+    }
+
+    /**
+     * 修改流程节点脚本
+     * 
+     * @param sysBpmNodeScript 流程节点脚本
+     * @return 结果
+     */
+    @Override
+    public int updateSysBpmNodeScript(SysBpmNodeScript sysBpmNodeScript)
+    {
+        sysBpmNodeScript.setUpdateTime(DateUtils.getNowDate());
+        sysBpmNodeScript.setUpdateBy(SecurityUtils.getUserId().toString());
+        return sysBpmNodeScriptMapper.updateSysBpmNodeScript(sysBpmNodeScript);
+    }
+
+    /**
+     * 批量删除流程节点脚本
+     * 
+     * @param ids 需要删除的流程节点脚本主键
+     * @return 结果
+     */
+    @Override
+    public int deleteSysBpmNodeScriptByIds(Long[] ids)
+    {
+        return sysBpmNodeScriptMapper.deleteSysBpmNodeScriptByIds(ids);
+    }
+
+    /**
+     * 删除流程节点脚本信息
+     * 
+     * @param id 流程节点脚本主键
+     * @return 结果
+     */
+    @Override
+    public int deleteSysBpmNodeScriptById(Long id)
+    {
+        return sysBpmNodeScriptMapper.deleteSysBpmNodeScriptById(id);
+    }
+}

+ 95 - 0
ruoyi-system/src/main/resources/mapper/system/SysBpmNodeScriptMapper.xml

@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.system.mapper.SysBpmNodeScriptMapper">
+    
+    <resultMap type="SysBpmNodeScript" id="SysBpmNodeScriptResult">
+        <result property="id"    column="id"    />
+        <result property="scriptKey"    column="script_key"    />
+        <result property="scriptFunctionName"    column="script_function_name"    />
+        <result property="scriptName"    column="script_name"    />
+        <result property="scriptFunctionCode"    column="script_function_code"    />
+        <result property="scriptType"    column="script_type"    />
+        <result property="scriptDescription"    column="script_description"    />
+        <result property="delFlag"    column="del_flag"    />
+        <result property="createBy"    column="create_by"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateBy"    column="update_by"    />
+        <result property="updateTime"    column="update_time"    />
+    </resultMap>
+
+    <sql id="selectSysBpmNodeScriptVo">
+        select id, script_key, script_function_name, script_name, script_function_code, script_type, script_description, del_flag, create_by, create_time, update_by, update_time from sys_bpm_node_script
+    </sql>
+
+    <select id="selectSysBpmNodeScriptList" parameterType="SysBpmNodeScript" resultMap="SysBpmNodeScriptResult">
+        <include refid="selectSysBpmNodeScriptVo"/>
+        where del_flag = '0'
+            <if test="scriptKey != null  and scriptKey != ''"> and script_key = #{scriptKey}</if>
+            <if test="scriptFunctionName != null  and scriptFunctionName != ''"> and script_function_name like concat('%', #{scriptFunctionName}, '%')</if>
+            <if test="scriptName != null  and scriptName != ''"> and script_name like concat('%', #{scriptName}, '%')</if>
+            <if test="scriptFunctionCode != null  and scriptFunctionCode != ''"> and script_function_code = #{scriptFunctionCode}</if>
+            <if test="scriptType != null "> and script_type = #{scriptType}</if>
+            <if test="scriptDescription != null  and scriptDescription != ''"> and script_description = #{scriptDescription}</if>
+    </select>
+    
+    <select id="selectSysBpmNodeScriptById" parameterType="Long" resultMap="SysBpmNodeScriptResult">
+        <include refid="selectSysBpmNodeScriptVo"/>
+        where id = #{id}
+    </select>
+        
+    <insert id="insertSysBpmNodeScript" parameterType="SysBpmNodeScript" useGeneratedKeys="true" keyProperty="id">
+        insert into sys_bpm_node_script
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="scriptKey != null">script_key,</if>
+            <if test="scriptFunctionName != null">script_function_name,</if>
+            <if test="scriptName != null">script_name,</if>
+            <if test="scriptFunctionCode != null">script_function_code,</if>
+            <if test="scriptType != null">script_type,</if>
+            <if test="scriptDescription != null">script_description,</if>
+            <if test="createBy != null">create_by,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="updateBy != null">update_by,</if>
+            <if test="updateTime != null">update_time,</if>
+            del_flag
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="scriptKey != null">#{scriptKey},</if>
+            <if test="scriptFunctionName != null">#{scriptFunctionName},</if>
+            <if test="scriptName != null">#{scriptName},</if>
+            <if test="scriptFunctionCode != null">#{scriptFunctionCode},</if>
+            <if test="scriptType != null">#{scriptType},</if>
+            <if test="scriptDescription != null">#{scriptDescription},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="createTime != null">#{createTime},</if>
+            '0'
+         </trim>
+    </insert>
+
+    <update id="updateSysBpmNodeScript" parameterType="SysBpmNodeScript">
+        update sys_bpm_node_script
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="scriptKey != null">script_key = #{scriptKey},</if>
+            <if test="scriptFunctionName != null">script_function_name = #{scriptFunctionName},</if>
+            <if test="scriptName != null">script_name = #{scriptName},</if>
+            <if test="scriptFunctionCode != null">script_function_code = #{scriptFunctionCode},</if>
+            <if test="scriptType != null">script_type = #{scriptType},</if>
+            <if test="scriptDescription != null">script_description = #{scriptDescription},</if>
+            <if test="updateBy != null">update_by = #{updateBy},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <update id="deleteSysBpmNodeScriptById" parameterType="Long">
+        update sys_bpm_node_script set del_flag = '2' where id = #{id}
+    </update>
+
+    <update id="deleteSysBpmNodeScriptByIds" parameterType="String">
+        update sys_bpm_node_script set del_flag = '2' where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </update>
+</mapper>

+ 1 - 0
ruoyi-ui/package.json

@@ -73,6 +73,7 @@
     "less": "^2.7.3",
     "less-loader": "^4.1.0",
     "lucide-vue": "^0.89.0",
+    "mockjs": "^1.1.0",
     "nprogress": "0.2.0",
     "quill": "1.3.7",
     "screenfull": "5.0.2",

+ 46 - 2
ruoyi-ui/src/api/bpmprocess/process.js

@@ -84,19 +84,63 @@ export function enableProcess(data) {
 // 新增流程配置
 export function addConfiguration(data) {
   return request({
-    url: '/system/configuration',
+    url: '/system/configuration/addProcessNodeConfiguration',
     method: 'post',
     data: data,
     baseURL: process.env.VUE_APP_BASE_API4,
+    // baseURL: 'http://192.168.110.59:8055',
   })
 }
 
 // 修改流程配置
 export function updateConfiguration(data) {
   return request({
-    url: '/system/configuration',
+    url: '/system/configuration/updateProcessNodeConfiguration',
     method: 'put',
     data: data,
     baseURL: process.env.VUE_APP_BASE_API4,
   })
 }
+
+// 查询流程节点脚本列表
+export function listScript(query) {
+  return request({
+    url: '/system/script/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询流程节点脚本详细
+export function getScript(id) {
+  return request({
+    url: '/system/script/' + id,
+    method: 'get'
+  })
+}
+
+// 新增流程节点脚本
+export function addScript(data) {
+  return request({
+    url: '/system/script',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改流程节点脚本
+export function updateScript(data) {
+  return request({
+    url: '/system/script',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除流程节点脚本
+export function delScript(id) {
+  return request({
+    url: '/system/script/' + id,
+    method: 'delete'
+  })
+}

+ 1 - 1
ruoyi-ui/src/main.js

@@ -71,7 +71,7 @@ import JsonExcel from 'vue-json-excel'
 
 // 自定义指令
 import Directives from '@/utils/directives'
-
+import './mock.js'
 
 // 全局方法挂载
 Vue.prototype.getDicts = getDicts

+ 5 - 0
ruoyi-ui/src/store/modules/user.js

@@ -6,6 +6,7 @@ const user = {
   state: {
     token: getToken(),
     name: '',
+    userId: '',
     avatar: '',
     roles: [],
     permissions: [],
@@ -20,6 +21,9 @@ const user = {
     SET_NAME: (state, name) => {
       state.name = name
     },
+    SET_USER_ID: (state, userId) => {
+      state.userId = userId
+    },
     SET_AVATAR: (state, avatar) => {
       state.avatar = avatar
     },
@@ -61,6 +65,7 @@ const user = {
       return new Promise((resolve, reject) => {
         getInfo().then(res => {
           const user = res.user
+          commit('SET_USER_ID', res.user.userId)
           const avatar = (user.avatar == "" || user.avatar == null) ? require("@/assets/images/profile.jpg") : process.env.VUE_APP_BASE_API + user.avatar;
           if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组
             commit('SET_ROLES', res.roles)

+ 371 - 0
ruoyi-ui/src/views/bpmprocess/scriptManage.vue

@@ -0,0 +1,371 @@
+<template>
+  <div class="app-container">
+    <el-form
+      :model="queryParams"
+      ref="queryForm"
+      size="small"
+      :inline="true"
+      v-show="showSearch"
+      label-width="68px"
+    >
+      <el-form-item label="脚本编码" prop="scriptKey">
+        <el-input
+          v-model="queryParams.scriptKey"
+          placeholder="请输入脚本编码"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="脚本方法名称" prop="scriptFunctionName">
+        <el-input
+          v-model="queryParams.scriptFunctionName"
+          placeholder="请输入脚本方法名称"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="脚本名称" prop="scriptName">
+        <el-input
+          v-model="queryParams.scriptName"
+          placeholder="请输入脚本名称"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="脚本描述" prop="scriptDescription">
+        <el-input
+          v-model="queryParams.scriptDescription"
+          placeholder="请输入脚本描述"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button
+          type="primary"
+          icon="el-icon-search"
+          size="mini"
+          @click="handleQuery"
+          >搜索</el-button
+        >
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery"
+          >重置</el-button
+        >
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['system:script:add']"
+          >新增</el-button
+        >
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['system:script:edit']"
+          >修改</el-button
+        >
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['system:script:remove']"
+          >删除</el-button
+        >
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['system:script:export']"
+          >导出</el-button
+        >
+      </el-col>
+      <right-toolbar
+        :showSearch.sync="showSearch"
+        @queryTable="getList"
+      ></right-toolbar>
+    </el-row>
+
+    <el-table
+      v-loading="loading"
+      :data="scriptList"
+      @selection-change="handleSelectionChange"
+    >
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="编号" align="center" prop="id" />
+      <el-table-column label="脚本编码" align="center" prop="scriptKey" />
+      <el-table-column
+        label="脚本方法名称"
+        align="center"
+        prop="scriptFunctionName"
+      />
+      <el-table-column label="脚本名称" align="center" prop="scriptName" />
+      <el-table-column
+        label="脚本方法体"
+        align="center"
+        prop="scriptFunctionCode"
+      />
+      <el-table-column label="脚本类型" align="center" prop="scriptType" />
+      <el-table-column
+        label="脚本描述"
+        align="center"
+        prop="scriptDescription"
+      />
+      <el-table-column
+        label="操作"
+        align="center"
+        class-name="small-padding fixed-width"
+      >
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['system:script:edit']"
+            >修改</el-button
+          >
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['system:script:remove']"
+            >删除</el-button
+          >
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total > 0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改流程节点脚本对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="脚本编码" prop="scriptKey">
+          <el-input v-model="form.scriptKey" placeholder="请输入脚本编码" />
+        </el-form-item>
+        <el-form-item label="脚本方法名称" prop="scriptFunctionName">
+          <el-input
+            v-model="form.scriptFunctionName"
+            placeholder="请输入脚本方法名称"
+          />
+        </el-form-item>
+        <el-form-item label="脚本名称" prop="scriptName">
+          <el-input v-model="form.scriptName" placeholder="请输入脚本名称" />
+        </el-form-item>
+        <el-form-item label="脚本方法体" prop="scriptFunctionCode">
+          <el-input
+            v-model="form.scriptFunctionCode"
+            type="textarea"
+            placeholder="请输入内容"
+          />
+        </el-form-item>
+        <el-form-item label="脚本描述" prop="scriptDescription">
+          <el-input
+            v-model="form.scriptDescription"
+            placeholder="请输入脚本描述"
+          />
+        </el-form-item>
+        <el-form-item label="删除标志" prop="delFlag">
+          <el-input v-model="form.delFlag" placeholder="请输入删除标志" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  listScript,
+  getScript,
+  delScript,
+  addScript,
+  updateScript,
+} from "@/api/bpmprocess/process";
+
+export default {
+  name: "Script",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 流程节点脚本表格数据
+      scriptList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        scriptKey: null,
+        scriptFunctionName: null,
+        scriptName: null,
+        scriptFunctionCode: null,
+        scriptType: null,
+        scriptDescription: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {},
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询流程节点脚本列表 */
+    getList() {
+      this.loading = true;
+      listScript(this.queryParams).then((response) => {
+        this.scriptList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        scriptKey: null,
+        scriptFunctionName: null,
+        scriptName: null,
+        scriptFunctionCode: null,
+        scriptType: null,
+        scriptDescription: null,
+        delFlag: null,
+        createBy: null,
+        createTime: null,
+        updateBy: null,
+        updateTime: null,
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map((item) => item.id);
+      this.single = selection.length !== 1;
+      this.multiple = !selection.length;
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加流程节点脚本";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids;
+      getScript(id).then((response) => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改流程节点脚本";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate((valid) => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateScript(this.form).then((response) => {
+              this.$modal.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addScript(this.form).then((response) => {
+              this.$modal.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$modal
+        .confirm('是否确认删除流程节点脚本编号为"' + ids + '"的数据项?')
+        .then(function () {
+          return delScript(ids);
+        })
+        .then(() => {
+          this.getList();
+          this.$modal.msgSuccess("删除成功");
+        })
+        .catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      this.download(
+        "system/script/export",
+        {
+          ...this.queryParams,
+        },
+        `script_${new Date().getTime()}.xlsx`
+      );
+    },
+  },
+};
+</script>

+ 2 - 2
ruoyi-ui/src/views/system/bpmnPro/components/Panel/components/ElementExecuteUser.vue

@@ -163,7 +163,7 @@ export default {
           }
           res.rows.forEach((item) => {
             this.exeUserValueList.push({
-              value: item.userName,
+              value: item.userId,
               label: item.nickName,
             });
           });
@@ -217,7 +217,7 @@ export default {
   display: flex;
   padding-right: 25px;
 }
-::v-deep .edit-item_label{
+::v-deep .edit-item_label {
   width: 90px !important;
 }
 </style>

+ 193 - 0
ruoyi-ui/src/views/system/bpmnPro/components/Panel/components/ElementUnusualTasks.vue

@@ -0,0 +1,193 @@
+<template>
+  <el-collapse-item name="element-unusual-tasks">
+    <template #title>
+      <collapse-title title="异常任务">
+        <lucide-icon name="FileX2" />
+      </collapse-title>
+      <number-tag :value="listeners.length" margin-left="12px" />
+    </template>
+    <div class="element-unusual-tasks">
+      <el-table border :data="listeners" style="width: 100%" height="200px">
+        <el-table-column label="序号" type="index" width="50" />
+        <el-table-column
+          label="执行脚本"
+          prop="scriptKey"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          label="触发方式"
+          prop="scriptTriggerType"
+          show-overflow-tooltip
+        />
+        <el-table-column label="操作" width="140">
+          <template slot-scope="{ row, $index }">
+            <el-button type="text" @click="openScriptModel($index, row)"
+              >编辑</el-button
+            >
+            <el-button type="text" @click="removeScript($index)"
+              >移除</el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <el-button
+        type="primary"
+        class="inline-large-button"
+        icon="el-icon-plus"
+        @click="openScriptModel(-1)"
+      >
+        添加执行监听
+      </el-button>
+    </div>
+
+    <el-dialog
+      :visible.sync="modelVisible"
+      title="添加可触发的异常任务"
+      width="640px"
+      append-to-body
+      destroy-on-close
+    >
+      <el-form
+        ref="formRef"
+        :model="newUnusualTask"
+        :rules="formRules"
+        class="need-filled"
+        aria-modal="true"
+      >
+        <el-form-item path="scriptKey" label="任务脚本">
+          <el-select v-model="newUnusualTask.scriptKey">
+            <el-option
+              v-for="{ label, value } in scriptKeyList"
+              :label="label"
+              :value="value"
+              :key="value"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item path="scriptTriggerType" label="事件触发类型">
+          <el-select v-model="newUnusualTask.scriptTriggerType">
+            <el-option
+              v-for="{ label, value } in scriptTriggerTypeList"
+              :label="label"
+              :value="value"
+              :key="value"
+            />
+          </el-select>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="modelVisible = false">取 消</el-button>
+        <el-button type="primary" @click="saveUnusualTask">确 认</el-button>
+      </template>
+    </el-dialog>
+  </el-collapse-item>
+</template>
+
+<script>
+import {
+  addUnusualTask,
+  getUnusualTasks,
+  getUnusualTasksType,
+  removeUnusualTask,
+  updateUnusualTask,
+  getUnusualTaskTableData,
+} from "@packages/bo-utils/myFieldUtil";
+import { getScriptType } from "@packages/bo-utils/scriptUtil";
+import EventEmitter from "@utils/EventEmitter";
+import { getActive } from "@packages/bpmn-utils/BpmnDesignerUtils";
+
+export default {
+  name: "ElementUnusualTasks",
+  data() {
+    return {
+      modelVisible: false,
+      listeners: [],
+      newUnusualTask: {},
+      formRules: {
+        scriptKey: {
+          required: true,
+          trigger: ["blur", "change"],
+          message: "异常任务不能为空",
+        },
+        scriptTriggerType: {
+          required: true,
+          trigger: ["blur", "change"],
+          message: "任务触发方式不能为空",
+        },
+      },
+      scriptKeyList: [
+        {
+          value: 1,
+          label: "缺货异常",
+        },
+        {
+          value: 2,
+          label: "人员异常",
+        },
+      ],
+      scriptTriggerTypeList: [
+        {
+          value: 0,
+          label: "手动",
+        },
+        {
+          value: 1,
+          label: "自动",
+        },
+      ],
+    };
+  },
+
+  mounted() {
+    this.reloadExtensionListeners();
+    EventEmitter.on("element-update", this.reloadExtensionListeners);
+  },
+  methods: {
+    reloadExtensionListeners() {
+      this.modelVisible = false;
+      this.newUnusualTask = {
+        scriptKey: "",
+        scriptTriggerType: 0,
+        // event: getDefaultEvent(getActive()),
+        // type: "class",
+      };
+      this._listenersRaw = getUnusualTasks(getActive());
+
+      this.listeners = getUnusualTaskTableData(this._listenersRaw);
+      console.log(this.listeners);
+    },
+
+    updateScriptType(value) {
+      this.newUnusualTask.script = {
+        scriptFormat: this.newUnusualTask.script?.scriptFormat,
+        scriptType: value,
+      };
+    },
+    removeScript(index) {
+      const listener = this._listenersRaw[index];
+      removeUnusualTask(getActive(), listener);
+      this.reloadExtensionListeners();
+    },
+    async saveUnusualTask(index) {
+      await this.$refs.formRef.validate();
+      this.activeIndex === -1
+        ? addUnusualTask(getActive(), this.newUnusualTask)
+        : updateUnusualTask(
+            getActive(),
+            this.newUnusualTask,
+            this._listenersRaw[this.activeIndex]
+          );
+      this.reloadExtensionListeners();
+    },
+
+    async openScriptModel(index, TaskData) {
+      this.activeIndex = index;
+      TaskData && (this.newUnusualTask = JSON.parse(JSON.stringify(TaskData)));
+      this.modelVisible = true;
+      await this.$nextTick();
+      this.$refs.formRef && this.$refs.formRef.clearValidate();
+    },
+  },
+};
+</script>

+ 5 - 2
ruoyi-ui/src/views/system/bpmnPro/components/Panel/index.vue

@@ -44,6 +44,7 @@ import ElementExecuteForm from "@packages/Panel/components/ElementExecuteForm";
 import ElementExecuteUser from "@packages/Panel/components/ElementExecuteUser";
 import ElementBeforeNode from "@packages/Panel/components/ElementBeforeNode";
 import ElementAfterNode from "@packages/Panel/components/ElementAfterNode";
+import ElementUnusualTasks from "@packages/Panel/components/ElementUnusualTasks";
 
 export default {
   name: "BpmnPanel",
@@ -62,6 +63,7 @@ export default {
     ElementExecuteUser,
     ElementBeforeNode,
     ElementAfterNode,
+    ElementUnusualTasks,
   },
   data() {
     return {
@@ -158,9 +160,10 @@ export default {
       // 添加执行表单
       isTaskOrUserTask(element) &&
         this.renderComponents.push(ElementExecuteForm);
+      !isProcess(element) && this.renderComponents.push(ElementUnusualTasks); //可处理异常
       isUserTask(element) && this.renderComponents.push(ElementExecuteUser);
-      // !isProcess(element) && this.renderComponents.push(ElementBeforeNode);
-      // !isProcess(element) && this.renderComponents.push(ElementAfterNode);
+      !isProcess(element) && this.renderComponents.push(ElementBeforeNode);
+      !isProcess(element) && this.renderComponents.push(ElementAfterNode);
     },
   },
 };

+ 12 - 5
ruoyi-ui/src/views/system/bpmnPro/components/Toolbar/tools/Save.vue

@@ -16,6 +16,8 @@ import { getProcessEngine } from "@packages/bpmn-utils/BpmnDesignerUtils";
 import EventEmitter from "@utils/EventEmitter";
 import { formDataValidate } from "@utils/formDataValidate";
 import { getNodeMsg } from "@packages/bo-utils/getNodeMsg";
+
+import moment from "moment";
 export default {
   name: "BpmnSave",
   computed: {
@@ -66,7 +68,6 @@ export default {
     },
     getProcessAsSvg() {
       let process = this.getProcess("svg");
-      console.log(process);
     },
     xmlStr2XmlObj(xmlStr) {
       var xmlObj = {};
@@ -122,6 +123,9 @@ export default {
       // 获取xml标签内容标签内容
       let xmlPro = await this.getProcess("xml");
       var xmlObj = this.xmlStr2XmlObj(xmlPro);
+
+      // this.saveNodeMsg(xmlObj);
+      // return;
       formData.startEventType =
         xmlObj
           .getElementsByTagName("bpmn:process")[0]
@@ -163,10 +167,11 @@ export default {
     },
     async saveNodeMsg(obj) {
       let data = getNodeMsg(obj);
-      if (!data.length) return;
-      data.forEach((item) => {
+      if (!data.bpmProcessConfigurationList.length) return;
+      data.bpmProcessConfigurationList.forEach((item) => {
         item.createBy = this.$store.state.user.name;
         item.nodeProcessKey = obj.id;
+        item.createTime = moment().format("YYYY-MM-DD HH:mm:ss");
       });
       try {
         let res = await addConfiguration(data);
@@ -176,9 +181,11 @@ export default {
     },
     async updateNodeMsg(obj) {
       let data = getNodeMsg(obj.warnings);
-      data.forEach((item) => {
-        item.createBy = this.$store.state.user.name;
+      if (!data.bpmProcessConfigurationList.length) return;
+      data.bpmProcessConfigurationList.forEach((item) => {
+        item.updateBy = this.$store.state.user.name;
         item.nodeProcessKey = obj.id || "";
+        item.updateTime = moment().format("YYYY-MM-DD HH:mm:ss");
       });
       try {
         let res = await updateConfiguration(data);

+ 74 - 10
ruoyi-ui/src/views/system/bpmnPro/components/bo-utils/getNodeMsg.js

@@ -1,4 +1,6 @@
 import { getProcessEngine } from "@packages/bpmn-utils/BpmnDesignerUtils";
+import { getModeler } from "@packages/bpmn-utils/BpmnDesignerUtils";
+import { v4 as uuidv4 } from "uuid";
 
 function getSecondStr(str) {
   return str.split(':')[1];
@@ -30,26 +32,32 @@ function getSecondStr(str) {
 // }
 
 export function getNodeMsg(xmlObj) {
+  // let moddle = getModeler.getModdle();
+  // console.log(moddle);
+  // return;
   let prefix = getProcessEngine();
   let { attributes, childNodes } = xmlObj
     .getElementsByTagName("bpmn:process")[0];
-  let res = [], attributeArray = ['nodeKey', 'nodeFormKey', 'nodeProcessKey', 'nodeType', 'nodeBefore', 'nodeAfter', 'nodeRolePremission', 'spare1', 'spare2', 'spare3', 'createBy', 'updateBy', 'remark'];
+  let bpmProcessConfigurationList = [], bpmNodeHandleUserList = [], bpmNodeScriptRelevanceList = [], attributeArray = ['nodeKey', 'nodeFormKey', 'nodeProcessKey', 'nodeType', 'nodeBefore', 'nodeAfter', 'nodeRolePremission', 'spare1', 'spare2', 'spare3', 'createBy', 'updateBy', 'remark'];
   childNodes.forEach((node) => {
-    console.dir(node);
+    let uuid = uuidv4();
+    bpmNodeScriptRelevanceList = [...bpmNodeScriptRelevanceList, ...getNodeException(node)];//获取节点脚本数据
+    bpmNodeHandleUserList = [...bpmNodeHandleUserList, ...getBpmNodeHandleUser(node, uuid)]
     let nodeObj = {
       nodeKey: '',
-      nodeFormKey: '',
-      nodeProcessKey: '',
-      nodeType: '',
+      nodeName: '',
+      nodeFormKey: '', //节点表单别名
+      nodeProcessKey: '', //流程别名
+      nodeType: '',   //节点类型(判断节点,正常节点..)根据字典维护
       nodeBefore: '',
       nodeAfter: '',
-      nodeRolePremission: '',
+      nodeRolePremission: uuid, //节点对应的角色权限字符
       spare1: '',
       spare2: '',
       spare3: '',
-      createBy: '',
-      updateBy: '',
-      remark: '',
+      createBy: '',  //创建者
+      updateBy: '',  //修改者
+      remark: '',    //节点描述
     }
     attributeArray.forEach(attr => {
       let tempAttr = prefix + ':' + attr
@@ -58,7 +66,63 @@ export function getNodeMsg(xmlObj) {
     nodeObj.nodeKey = node.id;
     nodeObj.nodeType = node.localName;
     if (nodeObj.nodeType == "sequenceFlow") return;
-    res.push(nodeObj)
+    bpmProcessConfigurationList.push(nodeObj)
   })
+  return {
+    bpmProcessConfigurationList,
+    bpmNodeHandleUserList,
+    bpmNodeScriptRelevanceList
+  };
+}
+
+function getNodeException(node) {
+  // console.dir(node);
+  let prefix = getProcessEngine();
+  let res = []
+  let { children } = node;
+  if (!children.length) return [];
+  children = Array.from(children);//数组化
+  let extensionElements = children.find((item) => item.nodeName == `bpmn:extensionElements`
+  )
+
+  if (!extensionElements) return [];
+  extensionElements.childNodes.forEach(item => {
+    if (item.nodeName == `${prefix}:unusualTask`) {
+      res.push({
+        scriptKey: item.attributes.scriptKey?.nodeValue,
+        scriptTriggerType: item.attributes?.scriptTriggerType?.nodeValue || 0
+      })
+    }
+  })
+  res.forEach((item) => {
+    item.nodeKey = node.id;
+  })
+  // console.log(res);
   return res;
+}
+
+
+function getBpmNodeHandleUser(node, uuid) {
+  if (node.localName !== 'userTask') return []
+  if (!node.attributes.length) return []
+  let res = {}, prefix = getProcessEngine();
+  res.virtuallyRole = uuid;
+  console.dir(node);
+  console.log(node.getAttribute('camunda:executeUserType'), 'aaaa');
+  let type = node.getAttribute('camunda:executeUserType');
+  switch (type) {
+    case '1':
+      res.executeUserNo = node.getAttribute('camunda:executeUser') + ','
+      break;
+    case '2':
+      res.executeUserNo = node.getAttribute('camunda:executeUser') + ','
+      break;
+    case '3':
+      res.realRole = node.getAttribute('camunda:executeUser') + ','
+      break;
+    default:
+      break;
+  }
+
+  return [res]
 }

+ 74 - 1
ruoyi-ui/src/views/system/bpmnPro/components/bo-utils/myFieldUtil.js

@@ -1,5 +1,10 @@
 import { catchError } from "@utils/printCatch";
 import { getModeler, getProcessEngine } from "@packages/bpmn-utils/BpmnDesignerUtils";
+import {
+  getExtensionElementsList,
+  addExtensionElements,
+  removeExtensionElements
+} from "@packages/bpmn-utils/BpmnExtensionElements";
 import { getBusinessObject, is, isAny } from "bpmn-js/lib/util/ModelUtil";
 import { add as collectionAdd } from "diagram-js/lib/util/Collections";
 
@@ -162,7 +167,7 @@ export function getBeforeNdoe(element) {
   return businessObject.get(`${prefix}:nodeBefore`);
 }
 
-// 节点后
+/* 节点后 */
 export function setAfterNdoe(element, value) {
   const prefix = getProcessEngine();
   const modeling = getModeler.getModeling();
@@ -180,3 +185,71 @@ export function getAfterNdoe(element) {
 }
 
 
+/* 异常任务 */
+
+export function getUnusualTasksContainer(element) {
+  const businessObject = getBusinessObject(element);
+  return businessObject?.get("processRef") || businessObject;
+}
+
+
+export function addUnusualTask(element, props) {
+  const prefix = getProcessEngine();
+  const moddle = getModeler.getModdle();
+  const businessObject = getUnusualTasksContainer(element);
+  const listener = moddle.create(`${prefix}:UnusualTask`, {});
+  updateTaskProperty(element, listener, props);
+  addExtensionElements(element, businessObject, listener);
+}
+
+// 获取异常任务表数据
+export function getUnusualTaskTableData(moddleList = []) {
+  const prefix = getProcessEngine();
+  let res = moddleList.map(item => {
+    return {
+      scriptKey: item?.$attrs[prefix + ':scriptKey'] || '',
+      scriptTriggerType: item?.$attrs[prefix + ':scriptTriggerType'] || 0
+    }
+  })
+  return res
+}
+
+function updateTaskProperty(element, listener, props) {
+  const modeling = getModeler.getModeling();
+  const prefix = getProcessEngine();
+  const { scriptKey, scriptTriggerType } = props;
+
+  const updateProperty = (key, value) =>
+    modeling.updateModdleProperties(element, listener, { [`${prefix}:${key}`]: value });
+
+  scriptKey && updateProperty("scriptKey", scriptKey);
+  scriptTriggerType && updateProperty("scriptTriggerType", scriptTriggerType);
+}
+// 修改任务
+export function updateUnusualTask(element, props, listener) {
+  removeExtensionElements(element, getUnusualTasksContainer(element), listener);
+  addUnusualTask(element, props);
+}
+
+// 移除一个异常任务脚本
+export function removeUnusualTask(element, listener) {
+  removeExtensionElements(element, getUnusualTasksContainer(element), listener);
+}
+
+// 获取异常任务列表
+export function getUnusualTasks(element) {
+  const prefix = getProcessEngine();
+  const businessObject = getUnusualTasksContainer(element);
+  return getExtensionElementsList(businessObject, `${prefix}:UnusualTask`);
+}
+
+// 获取异常任务类型
+export function getUnusualTasksType(listener) {
+  const prefix = getProcessEngine();
+  if (isAny(listener, [`${prefix}:UnusualTask`])) {
+    if (listener.get(`${prefix}:scriptKey`)) return "scriptKey";
+    if (listener.get(`${prefix}:scriptTriggerType`)) return "scriptTriggerType";
+  }
+  return "";
+}
+

+ 67 - 0
ruoyi-ui/src/views/system/bpmnPro/components/moddle-extensions/activiti.json

@@ -1010,6 +1010,73 @@
           "type": "String"
         }
       ]
+    },
+    {
+      "name": "UnusualTask",
+      "superClass": ["Element"],
+      "meta": {
+        "allowedIn": [
+          "bpmn:Task",
+          "bpmn:ServiceTask",
+          "bpmn:UserTask",
+          "bpmn:BusinessRuleTask",
+          "bpmn:ScriptTask",
+          "bpmn:ReceiveTask",
+          "bpmn:ManualTask",
+          "bpmn:ExclusiveGateway",
+          "bpmn:SequenceFlow",
+          "bpmn:ParallelGateway",
+          "bpmn:InclusiveGateway",
+          "bpmn:StartEvent",
+          "bpmn:IntermediateCatchEvent",
+          "bpmn:IntermediateThrowEvent",
+          "bpmn:EndEvent",
+          "bpmn:BoundaryEvent",
+          "bpmn:CallActivity",
+          "bpmn:SubProcess"
+        ]
+      },
+      "properties": [
+        {
+          "name": "scriptKey",
+          "isAttr": true,
+          "type": "String"
+        },
+        {
+          "name": "scriptTriggerType",
+          "isAttr": true,
+          "type": "String"
+        },
+        {
+          "name": "expression",
+          "isAttr": true,
+          "type": "String"
+        },
+        {
+          "name": "class",
+          "isAttr": true,
+          "type": "String"
+        },
+        {
+          "name": "delegateExpression",
+          "isAttr": true,
+          "type": "String"
+        },
+        {
+          "name": "event",
+          "isAttr": true,
+          "type": "String"
+        },
+        {
+          "name": "script",
+          "type": "Script"
+        },
+        {
+          "name": "fields",
+          "type": "Field",
+          "isMany": true
+        }
+      ]
     }
   ],
   "enumerations": []

+ 65 - 2
ruoyi-ui/src/views/system/bpmnPro/components/moddle-extensions/camunda.json

@@ -692,7 +692,8 @@
         "allowedIn": [
           "camunda:ServiceTaskLike",
           "camunda:ExecutionListener",
-          "camunda:TaskListener"
+          "camunda:TaskListener",
+          "camunda:UnusualTask"
         ]
       },
       "properties": [
@@ -746,7 +747,10 @@
       "name": "FailedJobRetryTimeCycle",
       "superClass": ["Element"],
       "meta": {
-        "allowedIn": ["camunda:AsyncCapable", "bpmn:MultiInstanceLoopCharacteristics"]
+        "allowedIn": [
+          "camunda:AsyncCapable",
+          "bpmn:MultiInstanceLoopCharacteristics"
+        ]
       },
       "properties": [
         {
@@ -815,6 +819,65 @@
         }
       ]
     },
+    {
+      "name": "UnusualTask",
+      "superClass": ["Element"],
+      "meta": {
+        "allowedIn": [
+          "bpmn:Task",
+          "bpmn:ServiceTask",
+          "bpmn:UserTask",
+          "bpmn:BusinessRuleTask",
+          "bpmn:ScriptTask",
+          "bpmn:ReceiveTask",
+          "bpmn:ManualTask",
+          "bpmn:ExclusiveGateway",
+          "bpmn:SequenceFlow",
+          "bpmn:ParallelGateway",
+          "bpmn:InclusiveGateway",
+          "bpmn:EventBasedGateway",
+          "bpmn:StartEvent",
+          "bpmn:IntermediateCatchEvent",
+          "bpmn:IntermediateThrowEvent",
+          "bpmn:EndEvent",
+          "bpmn:BoundaryEvent",
+          "bpmn:CallActivity",
+          "bpmn:SubProcess",
+          "bpmn:Process"
+        ]
+      },
+      "properties": [
+        {
+          "name": "expression",
+          "isAttr": true,
+          "type": "String"
+        },
+        {
+          "name": "class",
+          "isAttr": true,
+          "type": "String"
+        },
+        {
+          "name": "delegateExpression",
+          "isAttr": true,
+          "type": "String"
+        },
+        {
+          "name": "event",
+          "isAttr": true,
+          "type": "String"
+        },
+        {
+          "name": "script",
+          "type": "Script"
+        },
+        {
+          "name": "fields",
+          "type": "Field",
+          "isMany": true
+        }
+      ]
+    },
     {
       "name": "TaskListener",
       "superClass": ["Element"],

+ 64 - 1
ruoyi-ui/src/views/system/bpmnPro/components/moddle-extensions/flowable.json

@@ -760,6 +760,7 @@
         "allowedIn": [
           "flowable:ServiceTaskLike",
           "flowable:ExecutionListener",
+          "flowable:UnusualTask",
           "flowable:TaskListener",
           "bpmn:ServiceTask"
         ]
@@ -880,7 +881,10 @@
       "name": "FailedJobRetryTimeCycle",
       "superClass": ["Element"],
       "meta": {
-        "allowedIn": ["flowable:AsyncCapable", "bpmn:MultiInstanceLoopCharacteristics"]
+        "allowedIn": [
+          "flowable:AsyncCapable",
+          "bpmn:MultiInstanceLoopCharacteristics"
+        ]
       },
       "properties": [
         {
@@ -949,6 +953,65 @@
         }
       ]
     },
+    {
+      "name": "UnusualTask",
+      "superClass": ["Element"],
+      "meta": {
+        "allowedIn": [
+          "bpmn:Task",
+          "bpmn:ServiceTask",
+          "bpmn:UserTask",
+          "bpmn:BusinessRuleTask",
+          "bpmn:ScriptTask",
+          "bpmn:ReceiveTask",
+          "bpmn:ManualTask",
+          "bpmn:ExclusiveGateway",
+          "bpmn:SequenceFlow",
+          "bpmn:ParallelGateway",
+          "bpmn:InclusiveGateway",
+          "bpmn:EventBasedGateway",
+          "bpmn:StartEvent",
+          "bpmn:IntermediateCatchEvent",
+          "bpmn:IntermediateThrowEvent",
+          "bpmn:EndEvent",
+          "bpmn:BoundaryEvent",
+          "bpmn:CallActivity",
+          "bpmn:SubProcess",
+          "bpmn:Process"
+        ]
+      },
+      "properties": [
+        {
+          "name": "expression",
+          "isAttr": true,
+          "type": "String"
+        },
+        {
+          "name": "class",
+          "isAttr": true,
+          "type": "String"
+        },
+        {
+          "name": "delegateExpression",
+          "isAttr": true,
+          "type": "String"
+        },
+        {
+          "name": "event",
+          "isAttr": true,
+          "type": "String"
+        },
+        {
+          "name": "script",
+          "type": "Script"
+        },
+        {
+          "name": "fields",
+          "type": "Field",
+          "isMany": true
+        }
+      ]
+    },
     {
       "name": "TaskListener",
       "superClass": ["Element"],

+ 68 - 56
ruoyi-ui/src/views/tablelist/commonTable/queryfrom.vue

@@ -1,18 +1,29 @@
 <template>
-  <div>
+  <>
     <div class="cardBox" v-show="showCount">
-      <el-card 
-        shadow="hover" 
-        :body-style="{ padding: '20px'}" 
+      <el-card
+        shadow="hover"
+        :body-style="{ padding: '20px' }"
         class="card"
-        v-for="item in cardcountArr"
+        v-for="(item, index) in cardcountArr"
+        :key="index"
+      >
+        <el-tooltip
+          class="item"
+          effect="dark"
+          :content="item.title"
+          placement="top-start"
         >
-        <el-tooltip class="item" effect="dark" :content="item.title" placement="top-start">
           <div class="title">{{ item.title }}</div>
         </el-tooltip>
-          
-        <el-tooltip class="item" effect="dark" :content="item.description" placement="top-start">
-          <div class="description">{{ item.description}}</div>
+
+        <el-tooltip
+          class="item"
+          effect="dark"
+          :content="item.description"
+          placement="top-start"
+        >
+          <div class="description">{{ item.description }}</div>
         </el-tooltip>
 
         <div class="type">
@@ -21,7 +32,7 @@
         </div>
       </el-card>
     </div>
-    
+
     <el-form
       :model="queryParams.queryMap"
       ref="queryForm"
@@ -152,7 +163,7 @@
       </div>
 
     </el-form>
-  </div>
+  
 </template>
 
 <script>
@@ -201,60 +212,61 @@ export default {
       // card
       cardcountArr: [
         {
-          title: '标题1454654564548978784654456454545456489748787',
-          description: '描述11111154544564456486474787475465454564545454545454545',
-          type: '数量1',
-          count: 10
+          title: "标题1454654564548978784654456454545456489748787",
+          description:
+            "描述11111154544564456486474787475465454564545454545454545",
+          type: "数量1",
+          count: 10,
         },
         {
-          title: '标题2',
-          description: '描述256+56++46545646',
-          type: '已完成',
-          count: 20
+          title: "标题2",
+          description: "描述256+56++46545646",
+          type: "已完成",
+          count: 20,
         },
         {
-          title: '标题2',
-          description: '描述256+56++46545646',
-          type: '已完成',
-          count: 20
+          title: "标题2",
+          description: "描述256+56++46545646",
+          type: "已完成",
+          count: 20,
         },
         {
-          title: '标题2',
-          description: '描述256+56++46545646',
-          type: '已完成',
-          count: 20
+          title: "标题2",
+          description: "描述256+56++46545646",
+          type: "已完成",
+          count: 20,
         },
         {
-          title: '标题2',
-          description: '描述256+56++46545646',
-          type: '已完成',
-          count: 20
+          title: "标题2",
+          description: "描述256+56++46545646",
+          type: "已完成",
+          count: 20,
         },
         {
-          title: '标题2',
-          description: '描述256+56++46545646',
-          type: '已完成',
-          count: 20
+          title: "标题2",
+          description: "描述256+56++46545646",
+          type: "已完成",
+          count: 20,
         },
         {
-          title: '标题2',
-          description: '描述256+56++46545646',
-          type: '已完成',
-          count: 20
+          title: "标题2",
+          description: "描述256+56++46545646",
+          type: "已完成",
+          count: 20,
         },
         {
-          title: '标题2',
-          description: '描述256+56++46545646',
-          type: '已完成',
-          count: 20
+          title: "标题2",
+          description: "描述256+56++46545646",
+          type: "已完成",
+          count: 20,
         },
         {
-          title: '标题2',
-          description: '描述256+56++46545646',
-          type: '已完成',
-          count: 20
-        }
-      ],
+          title: "标题2",
+          description: "描述256+56++46545646",
+          type: "已完成",
+          count: 20,
+        },
+      ],,
     };
   },
   watch: {
@@ -322,26 +334,26 @@ export default {
 </script>
 
 <style scoped lang="scss">
-.cardBox{
+.cardBox {
   display: flex;
   align-content: space-between;
   flex-wrap: wrap;
   align-content: flex-start;
 }
-.card{
+.card {
   /* width:15%; */
   flex-basis: 15%;
   margin-bottom: 10px;
   margin-right: 15px;
-  .title{
+  .title {
     /* width:20%; */
     font-size: 18px;
     margin-bottom: 5px;
     white-space: nowrap;
-    overflow: hidden; 
+    overflow: hidden;
     text-overflow: ellipsis;
   }
-  .description{
+  .description {
     width: 70%;
     font-size: 13px;
     color: #9699a2;
@@ -353,11 +365,11 @@ export default {
     word-break: break-all;
     float: left;
   }
-  .type{
+  .type {
     float: right;
     margin-top: 10px;
   }
-  .count{
+  .count {
     font-size: 30px;
   }
 }