# 一、 背景

问题:针对客户选分支自定义的情况。中间选分支采用客开方案,但是后续流程提交仍然走bpm这边的提交逻辑。

针对上诉情况,需要解决以下几个问题:

  1. 弹窗之前的选分支数据,客开组件如何获取到
  2. 连续选人选分支的情况,需要不断走提交逻辑然后判断再选的复杂情况。
  3. 选分支组件客开,只支持单个注入替换,不支持批量的情况。

# 二、技术方案

针对客户自定义选分支交互功能,目前主要提供了两种方式:

  1. 客开只替换选分支弹窗交互功能。
  2. 客开完全替换提交类功能,实现提交+选分支等业务。

# 方案一: 只替换选分支组件

整体思路:在提交调用后,存在选分支的情况,调用第三方注册进来的选分支Promise函数,根据Promise.resolve获取到客开组件返回的选分支结果,然后在提交接口上携带上选分支信息继续执行,从而达到注册客开选分支组件。 1747134522657.png

# 方案二:整个提交逻辑第三方完全客开

整体思路:第三方注册行为执行之前的校验函数,完全客开提交按钮事件的提交逻辑,包含了选分支的组件等完全由第三方客开。

接入方案见文档:流程按钮扩展行为

# 方案对比:

优点 缺点 客开如何接入
只替换选分支组件 第三方只关心选分支信息的组装与返回,提交逻辑等仍然由bpm统一控制。 移动端交互1模式下:意见输入和选分支组件是合并在一个弹框的,需要第三方自己实现意见输入的功能。如果是移动端交互2模式的情况就不存在此问题,交互2意见输入和选分支是分离开的。 见此文档第三大点
提交逻辑完全客开 自由性更高,交互更自由。 接入成本高,需要实现提交+选分支等逻辑 流程按钮扩展行为 (opens new window)

根据方案优缺点对比,客开根据业务场景自行选择客开方案。

下面介绍的是如何只替换选分支弹窗交互的方案。

# 三、客开如何注册选分支组件

# 1. V8系统的框架

import { eventEmit, BpmPageContext } from '@seeyon/global';
   
type Dispatch = ({ type, payload }: {
    type: TField;
    payload: unknown;
}) => unknown
  
type BpmSdk = {
    // 选分支数据
    preMatchResponse:Record<string, any>;
}
  
  
interface EventParams {
  /** 需要自定义的流程行为 */
  actions: string[];
  /** 执行校验 **/
  func: (bpmAction: BpmAction, bpmSdk: BpmSdk ) => Promise<any>;
  type: 'SELECT_NEXT_HANDLER';
}
  
const Demo = ()=> {
  const { bpmEventId, store } = useContext(BpmPageContext);
   
  useEffect(() => {
    const eventName = `CUSTOM_ACTION_${bpmEventId}`;
    // 初始化注册选分支弹窗组件调起函数。
    eventEmit(eventName, {
      // 具体需要拦截的流程行为
      actions: ['SUBMIT', 'AGREE', 'DIS_AGREE'],
      func: (bpmAction, bpmSdk) => {
        // reolve状态由第客开方自己控制。调用resolve后会继续往下执行。
        return new Promise((resolve)=> resolve({
            state: 'success',
            data: {
            // 选分支数据
              preMatchRequestDto: {
                xxxx
              }
            }
        }));
      },
      type: 'SELECT_NEXT_HANDLER', // 必传
    });
  }, [bpmEventId]);
}

# 2. 外部系统接入:

外部系统接入是指在index.html中自行插入js的方式去实现客开功能。

const fn = (event)=>{
    const msgData = event.data;
    if(msgData.type === 'SUB_PAGE_MESSAGE') {
    // 流程相关信息
    const { bpmEventId } = msgData || {};
    // 自定义流程行为事件名称
    const eventName = `CUSTOM_ACTION_${bpmEventId}`;
    // 根据业务方需求自定义拦截流程行为
    window.SeeyonGlobal.eventEmit(eventName,{
      // 具体需要拦截的流程行为
      actions: ['SUBMIT', 'AGREE', 'DIS_AGREE'],
      func: (bpmAction, bpmSdk) => {
        // reolve状态由第客开方自己控制。调用resolve后会继续往下执行。
        return new Promise((resolve)=> resolve({
            state: 'success',
            data: {
            // 选分支数据
              preMatchRequestDto: {
                xxxx
              }
            }
        }));
      },
      type: 'SELECT_NEXT_HANDLER', // 必传
    });
   }
};
  
window.addEventListener('message', fn);
编撰人:xuxyyf、wensl