一、后端开发

1.1 流程按钮声明

  • iform-bpmn-biz/src/main/resources/conf/taskActionPlugins.xml
<taskAction name="countersignSign" supportType="both" actionType="other" script="true" init="false"> <!-- name是动作处理类中 -->
    <description value="iform.button.countersignSign"/><!-- 自定义按钮 -->
    <handlerClass value="taskActionCounterSignHandler"/> <!-- 对应处理动作类的beanId -->
</taskAction>

1.2 流程按钮定义

  • 动作类型枚举定义:com.ak.iform.bpmn.api.constant.ActionType.java
    /** 加签 */
    COUNTER_SIGN("countersignSign", "加签"),
  • 流程BPM常用变量定义:com.ak.iform.bpmn.api.constant.BpmConstants.java
    /**
     * 加签人员
     */
    String TASK_COUNTER_SIGN_USERS = "taskCounterSignUsers_";

    /**
     * 加签消息类型
     */
    String TASK_COUNTER_SIGN_MESSAGE_TYPE = "taskCounterSignMessageType_";

    /**
     * 加签原因
     */
    String TASK_COUNTER_SIGN_REASON = "taskCounterSignReason_";

    /**
     * 返回方式(原审批模式,返回给原执行人,直接往下流转)
     */
    String TASK_COUNTER_SIGN_RETURN_METHOD = "taskCounterSignReturnMethod_";
  • 流程操作类型枚举:com.ak.iform.bpmn.api.constant.BpmOperTypeEnum.java
,COUNTER_SIGN("countersignSign", "加签")
  • 流程按钮国际化
    • iform-provider-root\modules\provider-bpmn\src\main\resources\i18n\messages_bpmn.properties
iform.button.countersignSign=\u52A0\u7B7E
    • iform-provider-root\modules\provider-bpmn\src\main\resources\i18n\messages_bpmn_en_US.properties
iform.button.countersignSign=countersignSign
    • iform-provider-root\modules\provider-bpmn\src\main\resources\i18n\messages_bpmn_zh_CN.properties
iform.button.countersignSign=\u52A0\u7B7E

1.3 流程审批动作接口定义

  • com.ak.iform.bpmn.api.IBpmTaskCmdService.java
    /**
     * 处理任务-加签
     *
     * @param counterSignVo 加签动作参数对象
     * @return
     */
    @RequestMapping(value = "/countersignSign",method = RequestMethod.POST)
    APIResult<Void> countersignSign(
            @RequestBody @Valid BpmActionCounterSignVo counterSignVo,
            @RequestHeader(name = ParameterKey.HEADER_BPMN_PERMISSION_IGNORE, required = false, defaultValue = "false")
            Boolean ignorePermission);
  • com.ak.iform.bpmn.provider.BpmTaskCmdProvider.java

    @ApiOperation(value = "流程动作-加签", notes = "流程动作-加签",
              extensions = {@Extension(properties = {@ExtensionProperty(name = "submitCtrl", value = StringPool.Y)})})
      @Signature
      @Override
      public APIResult<Void> countersignSign(
              @ApiParam(name = "counterSignVo", value = "加签动作参数对象", required = true)
              @RequestBody BpmActionCounterSignVo counterSignVo,
              @RequestHeader(name = ParameterKey.HEADER_BPMN_PERMISSION_IGNORE, required = false, defaultValue = "false") Boolean ignorePermission) {
          APIResult<Void> result = new APIResult<>();
          IHandlerValidator<UniqueHandlerValidation> validator = null;
          try {
              String taskId = counterSignVo.getTaskId();
              // 获取cmd对象。
              IformTaskFinishCmd cmd =
                      BpmTaskUtil.getCmd(bpmDefineService, bpmFormService, bpmTaskRepository, bpmInstService, bpmDefineReader,
                              getRequest(), taskId, null, counterSignVo.getActionName(), null, counterSignVo.getReason(), counterSignVo.getData(), null,
                              null, null, 0, null, null, null, null, false, ignorePermission, null);
    
              if (logger.isDebugEnabled()) {
                  logger.debug("counterSign:{}", cmd.getTaskId());
              }
    
              List<String> notifyEmployeeIds = BpmCirculateUtil.conversionNotifyEmployeeIds(null, counterSignVo.getUserIds());
              // 加签人员
              cmd.addTransitVars(BpmConstants.TASK_COUNTER_SIGN_USERS, notifyEmployeeIds);
              // 消息类型
              cmd.addTransitVars(BpmConstants.TASK_COUNTER_SIGN_MESSAGE_TYPE, counterSignVo.getMsgTypes());
              //加签原因
              cmd.addTransitVars(BpmConstants.TASK_COUNTER_SIGN_REASON, counterSignVo.getReason());
              //返回方式(原审批模式,返回给原执行人,直接往下流转)
              if(StringUtil.isEmpty(counterSignVo.getReturnMethod())){
                  bpmTaskRepository.setForUpdate();
                  BpmTaskPo bpmTask = bpmTaskRepository.get(taskId);
                  bpmTaskRepository.removeForUpdate();
                  // 查询节点
                  IBpmNodeDefine taskNodeDef = bpmDefineReader.getNode(bpmTask.getProcDefId(), bpmTask.getNodeId());
                  // 检查
                  List<Button> buttons = taskNodeDef.getButtonList();
                  for (Button button : buttons){
                      if(button.getAlias().equals("countersignSign")){
                          counterSignVo.setReturnMethod(button.getCountersignSignMode());
                          break;
                      }
                  }
                  if(StringUtil.isEmpty(counterSignVo.getReturnMethod())){
                      counterSignVo.setReturnMethod(BpmTaskAssignPo.ASSIGN_TYPE_ORIG);
                  }
              }
              cmd.addTransitVars(BpmConstants.TASK_COUNTER_SIGN_RETURN_METHOD, counterSignVo.getReturnMethod());
              validator = BpmUtil.validationForCount(bpmTaskRepository);
              BpmUtil.validation(validator, cmd.getTaskId());
              //执行加签审批动作
              bpmTaskActionService.finishTask(cmd);
              result.setMessage(I18nUtil.getMessage("com.ak.iform.bpmn.provider.BpmTaskProvider.complete", ""));
          } catch (LockedTaskException e) {
              setExceptionResult(result, StateEnum.ERROR_BPMN_LOCKED_TASK.getCode(),
                      StateEnum.ERROR_BPMN_LOCKED_TASK.getText(), e);
          } catch (SuspendException e) {
              setExceptionResult(result, StateEnum.ERROR_BPMN_SUSPEND_TASK.getCode(),
                      StateEnum.ERROR_BPMN_SUSPEND_TASK.getText(), e);
          } catch (PermissionException e) {
              setExceptionResult(result, StateEnum.ERROR_BPMN_PERMISSION_TASK.getCode(),
                      StateEnum.ERROR_BPMN_PERMISSION_TASK.getText(), e);
          } catch (NoTaskException e) {
              setExceptionResult(result, StateEnum.ERROR_BPMN_NO_TASK.getCode(),
                      String.format(StateEnum.ERROR_BPMN_NO_TASK.getText(), counterSignVo.getTaskId()), e);
          } catch (HandlingTaskException e) {
              setExceptionResult(result, StateEnum.ERROR_BPMN_HANDLING_TASK.getCode(),
                      StateEnum.ERROR_BPMN_HANDLING_TASK.getText(), e);
          } catch (Exception e) {
              setExceptionResult(result, StateEnum.ERROR_BPMN_TASK.getCode(), StateEnum.ERROR_BPMN_TASK.getText(), e);
          } finally {
              HandlerValidationUtil.processAfterInvoke(validator);
          }
          return result;
      }

1.4 处理类开发

  • 继承com.ak.iform.bpmn.handler.userTask.AbstractTaskActionHandler
  • 实现父类的preActionHandler方法(前置方法 可选), execute方法(执行方法 可选), afterActionHandler方法(后置方法 可选)

1.5 消息模版

  • 消息模板增加加签消息模板sql

    INSERT INTO `iform_msg_tpl` (`id_`, `name_`, `key_`, `type_key_`, `sub_type_key_`, `is_default_`, `subject_`, `plain_`, `html_`, `create_by_`, `create_time_`, `create_org_id_`, `update_by_`, `update_time_`, `wechat_`, `tenant_id_`, `dingtalk_`)
    VALUES ('139728732518351022', '加签[默认]', 'bpmCountersignSignTaskTask-default', 'countersignSignTask', NULL, 'Y', '加签通知', '加签通知,${sender}将任务:${taskSubject}加签给您', '加签通知:<br />${sender}邀请你参与任务<a href=\"${baseUrl}/platform/bpmn/form?taskId=${taskId}\" target=\"_blank\">${taskSubject}</a>,加签原因:${cause}', '1', '2017-03-02 19:51:21', NULL, NULL, NULL, '加签通知:<br />${sender}邀请你任务<a href=\"${baseUrl}/platform/bpmn/form?taskId=${taskId}\" target=\"_blank\">${taskSubject}</a>,加签原因:${cause}', '-999', '加签通知:${sender}邀请你参与任务 ${baseUrl}/platform/bpmn/form?taskId=${taskId} ${taskSubject},加签原因:${cause}');
  • 增加消息模版分类: com.ak.iform.bpmn.api.constant.TemplateType.java

BPM_COUNTER_SIGN_TASK("countersignSignTask","加签通知"),

细节后续完善

二、前端开发

2.1 前端事件处理逻辑举例

例如:增加“驳回指定节点” 按钮,下面按这个举例

1、先增加按钮逻辑

代码路径:src\business\platform\bpmn\form\button.js

2、再增加按钮具体处理逻辑

代码路径: src\business\platform\bpmn\form\action.js

内嵌url表单按钮处理
作者:caoyl  创建时间:2025-05-12 09:38
最后编辑:caoyl  更新时间:2025-05-12 11:21