# 流程详情页面-二开口子

# 一、前端JSSDK

> [流程详情JSSDK文档](https://weapp.eteams.cn/ecode/playground/doc/share/view/988383343450701824)

- 主要包含获取流程信息、流程操作按钮、流程提交等操作触发及拦截等


> 表单相关jssdk文档
- 主要包含流程表单字段相关，取值、赋值、明细操作等


# 二、前端组件复写、事件埋点

## 2.1、流程详情PC各区块扩展

> 用途及二开场景：

- 可满足在标准框架内，各区块前置、后置追加显示自定义组件

> 使用说明
- 复写FPDevBlockSlot组件
- 组件props取slotPlace、blockType控制渲染位置
- 其中slotPlace可区分前置、后置
- 其中blockType可区分 区块组件名称

> FPDevBlockSlot组件props说明

| 参数 | 说明 |类型
| ---- | ---- | ---- |
|slotPlace |插槽位置|'before','after'
|blockType | 区块名 | BlockType 
|baseParam|基础参数|any|
|visibleOperMenus |流程按钮合集 | any[]

> blockType名称说明

| 参数 | 说明 |
| ---- | ---- |
|SignInput |意见输入框
|OperArea | 操作按钮区
|Prompts|顶部信息提示区
|RelateForm |表单主体区
|HistoryApply|历史申请区
|SignComment | 流转意见列表区


> 参考代码样例、二开效果
```
regOvComponent('weappWorkflow', 'FPDevBlockSlot', (Com) => {
  return React.forwardRef((props, ref) => {
    if (props.slotPlace === 'after' && (props.blockType === "Prompts" || props.blockType === "SystemArea" )) {
        return (
            <React.Suspense fallback={() => {}}>
                <FlowPageAlert  message= {`${props.blockType} - 自定义插入组件`} type="info"/>
            </React.Suspense>
        )
    }
    return <Com ref={ref} {...props} />;
    });
}, 1);
```

![](/api/ecode/resource/view/${appRes}/1713236462-image.png)


## 2.2、打开流程详情查看/审批页面，并支持提交后刷新

### 2.2.1、PC端

> 推荐方案：使用标准封装的方法

> openNewViewPage方法参数说明

- openNewViewPage = (requestId: string, urlParams = {}, reloadEvent: (Function | null) = null, isFull : boolean）

| 参数 | 说明 |
| ---- | ---- |
|requestId | 请求id/流程实例id
|urlParams | 可选，会拼接作为url参赛，如果是兼岗/主次账号打开需传递对应身份参赛
|reloadEvent| 可选，打开的流程提交后触发的事件，可实现列表刷新
|isFull | 固定传true

```
window.weappUtils.corsImport('@weapp/workflow').then(res =>{
 const openNewViewPage = res.Util.PCFlowPageUtil.openNewViewPage;
 openNewViewPage('打开的requestid', {}, ()=>{console.log('刷新函数')}, true);
});

```

> 其他方案：自身window.open打开，单独注册刷新事件

```
window.open('/sp/workflow/flowpage/view/:requestId');

//列表页面定义指定名称window方法，提交会触发

function _Opener_ebComReload(){
	/** 如果页面存在eb搭建列表，eb列表也可能定义此函数，二开再定义会存在覆盖  **/
}

```

### 2.2.2、移动端

> 最低要求24.1001基线

> mOpenLinkViewRequest方法参数说明

- mOpenLinkViewRequest = (requestId: string, urlParams:any = {}, reloadFn?: ()=>{}, openType?:number)

| 参数 | 说明 |
| ---- | ---- |
|requestId | 请求id/流程实例id
|urlParams | 可选，会拼接作为url参赛，如果是兼岗/主次账号打开需传递对应身份参赛
|reloadEvent| 可选，打开的流程提交后触发的事件，可实现列表刷新（*目前仅支持E10-app）
|openType| 可选，打开方式，传递1为当前页面跳转，2为webview弹窗，默认为2

> 默认openType=2：

- 以webview新窗口方式打开，优点：打开再返回原页面不会重新加载
- 如果是EM-App移动端，建议传递2；传递的reloadEvent在流程提交后会触发调用
- 如果是钉钉、企微、飞书，能打开，但刷新函数不行，依赖对方app支持广播通信
- 第三方App，需提前接入适配webview方式打开
- 公用企业微信默认仅支持单webview，方法内会判断公有企微走location.href达到提交后回到原页面场景

> 传递openType=1：

- 始终以location.href方式跳转
- 打开-返回，原页面会刷新
- 打开-流程提交后，回到原页面，原页面也是刷新

```
window.weappUtils.corsImport('@weapp/workflow').then(res =>{
 const mOpenLinkViewRequest = res.Util.MFlowPageUtil.mOpenLinkViewRequest;
 mOpenLinkViewRequest('打开的requestid', {}, ()=>{console.log('刷新函数')}, 2);
});

```



## 2.3、移动端新建/列表打开详情走webview弹出新页面

> 用途及二开场景
- 仅移动端，标准是走路由模式，支持二开ecode控制走webview新窗口模式
- 新窗口模式，第三方App需对接组件库的openLink、关闭、广播等事件

> 开启方式：ecode新建项目entry.js粘贴下面内容即可

```
import { regHook } from '@weapp/utils';

const enableWebview = () =>{
  window.weappWorkflow?.writeConfig?.('MFP_Enable_WebViewOpen', true);
}

enableWebview();

regHook('weappWorkflow', 'libReady', enableWebview);
```

> 使用webview新窗口方式打开，支持在列表页面注册广播事件，实现刷新

- 注：广播事件需App本身支持，且对接组件库

```
import { weappSDK } from "@weapp/utils";

weappSDK.exec("registerBroadcast", {
    name:'FP_RELOAD_LIST', 
    success: ()=>{
        /** 详情需要刷新的时候触发，比如提交从待办消失、抄送点击查看从待办消失 */
    },
});


weappSDK.exec("registerBroadcast", {
    name:'FP_WEBVIEW_CLOSE', 
    success: ()=>{
        /** webview关闭的时候触发 */
    },
});
```

## 2.4、列表/新建等打开流程详情方式复写

> 用途及二开场景
- 标准列表、新建，打开加载流程详情方法复写
- 可实现不打开标准的flowpage页面，改为打开自定义地址

> 使用说明
- ecode复写增加钩子函数，标准埋点优先取钩子函数逻辑执行
- 钩子函数，props可取是否移动端、打开方式、是否创建、原函数等参数，实现按需控制复写范围及是否执行原事件
- pc端钩子使用OpenFlowPageWay，移动端钩子使用MOpenFlowPageWay

> 钩子函数参数ts类型

```
declare type OpenFlowPageWay = 'spa'|'right'|'middle'|'route';

//打开方式复写参数对象
export type OpenWayHookParams = {
    isCreate: boolean,      //是否新建
    workflowId?: string,      //新建-工作流id
    requestId?: string,     //查看-请求id
    urlParams: any,        //原url参数
    isMobile?: boolean,      //是否移动端
    way:OpenFlowPageWay,    //原打开方式
    originFn: ()=>void,       //不复写，执行标准函数
}
```

> 参考代码样例

```
import { regHook } from '@weapp/utils';

regHook('weappWorkflow', 'OpenFlowPageWay', (params)=>{
	const { isCreate,isMobile,workflowId,requestId,urlParams,way,originFn } = params;
  /** TODO **/
  //继续执行原打开逻辑
  originFn();
});
```

## 2.5、意见输入框复写

> 用途及二开场景
- 流程详情各入口使用的意见框组件，可复写 替换、包装等展示多形态
- 顶部/底部显示意见框、表单设计器布局中意见输入框控件、退回/转发等操作弹窗使用的意见框，均可复写，需通过scene参数识别来源


> scene场景标示参考

```
export enum SignInputScene {
    frameShow = 'frameShow',    //详情框架始终展示
    formLayout = 'formLayout',  //表单设计器
    rejectDialog = 'rejectDialog',  //退回弹窗
    forwardDialog = 'forwardDialog',    //转发弹窗
    ccDialog = 'ccDialog',      //抄送弹窗
    turnTodoDialog = 'turnTodoDialog',      //转办弹窗
    askOpinionDialog = 'askOpinionDialog',      //意见征询
    circulateDialog = 'circulateDialog',        //传阅弹窗
}
```

> 意见输入框组件复写-样例

```
import React from 'react';
import { regOvProps, regOvComponent } from '@weapp/utils';

//复写组件内容
regOvComponent('weappWorkflow', 'FPSignInput', (Com) => {
    return React.forwardRef((props, ref) => {
    		const { scene } = props;
        //详情框架显示意见输入框改写
        if(scene == 'frameShow'){
        		return (
            	<>
              	<div>自定义内容</div>
                <Com ref={ ref } {...props} />
              <>
            )
        }
        //不复写返回原组件
        return <Com ref={ ref } {...props} />;
    });
});
```

> 意见输入框组件props复写

- 实现弹窗操作不自动复制带入外部意见框内容，控制props参数forbidCopy

```
import React from 'react';
import { regOvProps, regOvComponent } from '@weapp/utils';

//复写组件props
regOvProps('weappWorkflow', 'FPSignInput', (props) => {
    //控制转发弹窗不复制，也可不限制
    if (props.scene === 'forwardDialog') {
        props.forbidCopy = true;
    }
    return props;
});

```

## 2.6、移动端详情内容区复写

> 用途及二开场景
- 仅适用于移动端，除顶部页签及底部按钮区域外，中间内容区复写
- 场景一：移动端详情扩展页签，页签需在内容区域显示

> 样例

```
import React from 'react';
import { regOvProps, regOvComponent } from '@weapp/utils';

//复写组件内容
regOvComponent('weappWorkflow', 'MFPContent', (Com) => {
    return React.forwardRef((props, ref) => {
        const wffpSdk = window.weappWorkflow.getFlowPageSDK();
        const { workflowId } = wffpSdk.getBaseParam();
        //限定范围复写
        if (workflowId == '**') {
            return (
            	<>
                    <Com ref={ref} {...props} />
                    <div>自定义页签组件，页签切换隐藏原Com组件显示此组件</div>
              <>
            )
        }
        //不复写返回原组件
        return <Com ref={ref} {...props} />;
    });
});
```

## 2.7、移动端读取pc布局，控制缩放比

> 用途说明

- 标准支持移动端读取pc布局，读取pc布局会根据【手机屏幕宽度/pc布局总宽度】得到缩放比，默认以缩放形式一屏展示表单
- pc布局总宽度算法：如果列表都是绝对宽度，取列宽之和；如果列宽含百分比，固定为1000px

> 支持通过ecode控制缩放比，覆盖标准效果

> 下面代码复制放入ecode前置加载-发布即可，具体缩放比例根据实际情况调整

```
import { regOvProps } from '@weapp/utils';

const ovFlowPagePropsFn = (props) => {
  window.weappWorkflow?.writeConfig('MFP_PCLayout_Scale', {
    initial: '0.8',   //读取pc布局，默认进入的缩放比；标准为根据列表计算
    minimum: 0.8,   //读取pc布局，最小缩放比；标准默认为0.1【如果列宽含百分比，此值设置小于initial的无效】
    maximum: 3,   //读取pc布局，最大缩放比；标准默认为5.0
  });
	return props;
}


// 对流程详情移动端生效
regOvProps('weappWorkflow', 'MFPMainTab', ovFlowPagePropsFn, 0);
```

## 2.8、提交后显示流程图并停留，实现定时关闭

> 用户说明
- 提交后配置显示流程图并停留，props复写组件实现定时关闭【24.0901基线以上】

![](${appMdRes}/1724123691-image.png)

> 代码copy放ecode前置加载发布

```
import { regOvProps } from '@weapp/utils';

const fn = (props) => {
    props.stopChartNoticeMsg = 'ecode复写，停留在流程图，5s自动关闭';       //提示信息
    props.stopChartAutoCloseTime = 5000;    //定时关闭时间
    return props;
}
regOvProps('weappWorkflow', 'FPChartRoute', fn);    //pc端生效

regOvProps('weappWorkflow', 'MFPChartRoute', fn);   //移动端生效
```
## 2.9 屏蔽移动端流程回到顶部、底部按钮
> 标准默认开启，可以通过ecode屏蔽


![](${appMdRes}/1735094669-image.png)
```
import { regOvProps } from '@weapp/utils';

const ovFlowPagePropsFn = (props) => {
  window.weappWorkflow?.writeConfig('MFP_Enable_BackToTop', {
    enable:false //关闭移动端回到顶部按钮
  });
	return props;
}


// 对流程详情移动端生效
regOvProps('weappWorkflow', 'MFPMainTab', ovFlowPagePropsFn, 0);
```

## 2.10 移动端提交后配置自定义页面，跳转方式由iframe改为location

> 2512及后续基线默认走location，无需增加参数或者ecode

> 2501～2511基线，可通过下面方式配置，实现提交后配置自定义页面走location方式跳转

> 方式一：

- 配置的提交后自定义url地址，增加参数&submitForwardForbidIFrame=1

> 方式二：

- 下面代码复制放入ecode，前置加载-发布移动端即可，全部以location.replace方式跳转

```
import { regHook } from '@weapp/utils';

regHook('weappWorkflow', 'libReady', ()=>{
  window.weappWorkflow?.writeConfig?.('MFP_SubmitForward_ForbidIFrame', true);
});
```
## 2.11 屏蔽创建流程切换身份入口

> 版本要求：2502基线及以上

![](${appMdRes}/1740291881-image.png)

```javascript
import { regHook } from '@weapp/utils';

regHook('weappWorkflow', 'libReady', ()=>{
  window.weappWorkflow?.writeConfig?.('FP_ForbidCreate_SwitchIdentity', true);
});
```

## 2.12 控制移动端底部按钮形态

> 版本要求：2502基线及以上

> 移动端-底部按钮控制，含按钮显示个数、按钮排列顺序、更多按钮位置、按钮所占空间

- 标准默认显示2个按钮，可通过ecode实现显示1～4个按钮，超过范围无效
- 可控制按钮从左往右排列
- 可控制“更多”按钮显示在按钮组左侧或右侧
- 可控制 意见笔触按钮、更多按钮所占空间


![](${appMdRes}/1741076416-image.png)

> 参考下面案例，代码复制放ecode移动端前置加载

```
import {regHook} from '@weapp/utils';

const flowPageLoadFn = (params) => {
  const wffpSdk = window.weappWorkflow.getFlowPageSDK();
  wffpSdk.controlBottomBtn({
      num: 2, //默认显示按钮个数，默认为2个，最少1个，最多4个
      btnFloat:  'right',  //按钮排列顺序，默认right，只能传递right或者left，left表示从左往右排列
      moreBtnPlace: 'left',  //更多按钮显示位置，默认left显示在按钮组左侧，只能传递right或者left
      signBtnColSpan: 4,  //笔触存在时，笔触所占分栏数（总共24分栏，值越大则按钮组所占空间越小，建议值: 3～6）
      moreBtnColSpan: 4,  //笔触存在时，更多按钮所占分栏数 （总共24分栏，值越大则按钮组所占空间越小，建议值: 3～6）
      signHideMoreBtnColSpan: 6,  //笔触不存在时，更多按钮所占分栏数 （总共24分栏，值越大则按钮组所占空间越小，建议值: 3～6）
  });
}

//对流程详情移动端端生效
regHook('weappWorkflow', 'MFPMainTabWillMount', flowPageLoadFn);

```
## 2.13 屏蔽移动端悬浮按钮组中指定按钮

> 下面代码复制放入ecode，前置加载-发布移动端（版本要求：2509基线及以上） 



![](${appMdRes}/1757383773-image.png)

```javascript
import { regOvProps } from '@weapp/utils';

//btnKey 指定按钮， enable控制隐藏
const overrideBtnCfg = (btns = []) => btns.map(item => 
  item.btnKey === 'SwitchLayout' ? { ...item, enable: false } : item
);


const ovPropsFn = props => ({
  ...props,
  overrideBtnCfg
});

regOvProps('weappWorkflow', 'MWFFPQuickMenus', ovPropsFn, 0);
```

## 2.14 屏蔽移动端签字意见框底部按钮

> 下面代码复制放入ecode，前置加载-发布移动端

![](${appMdRes}/1759125196-image.png)

```javascript
import { regHook } from '@weapp/utils';

regHook('weappWorkflow', 'libReady', ()=>{
  window.weappWorkflow?.writeConfig?.('MFP_SignInputActionConfig', {
      hideActions:['upload']
  });
});
```
>hideActions参数说明

| 参数值 | 说明 |
| ---- | ---- |
|address|位置
|upload|附件上传|
|emoticon|表情|
|associated|事项关联|
|at|@提到|
|recording|录音|
|voiceToText|语音转文字|
|fullText|全文批注|

## 2.15 意见评论列表打印支持横向展示

> 下面代码复制放入ecode，前置加载-发布PC端 （版本要求：2511基线及以上） 


![](${appMdRes}/1761182848-image.png)
```javascript
import { regHook } from '@weapp/utils';

regHook('weappWorkflow', 'libReady', ()=>{
  window.weappWorkflow?.writeConfig?.('FP_CommentPrint_Config', {
      isHorizontal:true,
      columns:3,
        printColumnTemplates:{
        template2:2,// 指定模板2控制显示2列
        template7:1,// 指定模板7控制显示1列
      }
  });
})
```
>参数说明

| 参数值 | 说明 | 默认值
| ---- | ---- |---- |
|isHorizontal|是否开启横向| false|
|columns|横向展示列数|4|
|printColumnTemplates|按模板单独配置横向展示列数|-|


## 2.16 PC端紧急程度支持平铺展示

> 下面代码复制放入ecode，前置加载-发布PC端 （版本要求：2605基线及以上）


![](${appMdRes}/1775785281-image.png)

```javascript
import { regHook } from '@weapp/utils';

regHook('weappWorkflow', 'libReady', () => {
   window.weappWorkflow?.writeConfig?.('FP_RequestLevel_FlatRadio',true);
});
```

## 2.17 流程详情页签新建不读取默认页签配置/移动端默认页签读取pc

> 可满足两个场景

- 流程新建时，始终默认为流程表单页签，不读取工作流页签配置的默认页签；保存/提交后才读取默认页签配置
- 移动端不支持配置默认页签，读取pc的默认页签配置

> 以下代码复杂放ecode （版本要求：2604基线及以上）

```
import { regHook } from '@weapp/utils';

regHook('weappWorkflow', 'libReady', () => {
  window.weappWorkflow?.writeConfig?.('FP_Tab_Config', {
    createIgnoreDefTab: true,  //true表示新建时，不读取默认页签配置
    mobileReadPcDefTab: true, //true表示移动端也读取pc的默认页签配置
  });
});
```

# 三、组件封装暴露

## 3.1、单独调用表单修改日志组件

> 展示效果-弹框模式

![](/api/ecode/resource/view/${appRes}/1712474397-image.png)

> 展示效果-非弹框模式

![](/api/ecode/resource/view/${appRes}/1712474470-image.png)

> 代码演示
```
<CorsComponent
        weId={`${this.props.weId || ''}_1xjgso`}
        app='@weapp/workflow'
        compName="FlowPage"
        wfCompName = "FormLog"
        requestId = {''}
        workflowId = {''}
    />
```

> 组件Prop参数说明

| 参数 | 说明 |类型| 是否必填 | 默认值 |
| ---- | ---- | ---- | ---- | ---- |
|requestId |流程请求id|string |是|-|
|workflowId | 流程id| string|是|-|
|isDialog|是否弹框模式|boolean|否|false|
|closeCallBack |弹框关闭回调|(type: string, state: boolean) => void |否|-|
|dialogProps|弹框相关props|DialogType|否|-|

>以下属性仅对按节点范围查看表单日志生效

![](/api/ecode/resource/view/${appRes}/1712461051-image.png)
| 参数 | 说明 |类型| 是否必填 | 默认值 |
| ---- | ---- | ---- | ---- | ---- |
|menuValue|当前选择节点|string（为'all'默认显示全部节点）|否|'all'|
|afterLoadParam|组件加载完成回调|(data:RequestResult) => void|否|-|

```
interface RequestResult {
    viewType:'FIELD_AUTH' | 'NODE_RANGE', //按权限 | 按节点范围
    nodeId:string,//当前身份节点
    nodeMultiList:any[] //所有节点信息列表
}
```
## 3.2、单独引入移动端签字意见列表
> 展示效果

![](${appMdRes}/1749469570-image.png)
> 示例代码
```
<CorsComponent
     app='@weapp/workflow'
     compName="FlowPage"
     wfCompName = "MComment"
     requestId ='1143246373753200645'
 />
```
>组件props参数说明

| 参数 | 说明 |类型| 是否必填 | 默认值 |
| ---- | ---- | ---- | ---- | ---- |
|wfCompName|组件名称|MComment|是|-|
|requestId|流程请求id，新建流程不支持展示|string|是|-|



## 3.3、单独引入移动端流程图
> 展示效果


![](${appMdRes}/1749470025-image.png)
> 示例代码
```
<CorsComponent
    app='@weapp/workflow'
    compName="FlowPage"
    wfCompName = "MChart"
    isRoute = {false}
    requestId ='1143246373753200645'
    workflowId = '1139533980001493064'
    chartProps = {{
       initParams:{
       	  isCreate:false
        }
     }}
 />
```
>组件props参数说明

| 参数 | 说明 |类型| 是否必填 | 默认值 |
| ---- | ---- | ---- | ---- | ---- |
|wfCompName|组件名称|MChart|是|-|
|requestId|	流程请求id|string|是|-|
|workflowId|流程id|string|是|-|
|isCreate|流程是否新建状态|boolean|是|false|
|isRoute|是否路由模式加载|boolean|否|true|

## 3.4、单独引入移动端流程状态
> 展示效果


![](${appMdRes}/1749470302-image.png)
> 示例代码
```
<CorsComponent
  app='@weapp/workflow'
  compName="FlowPage"
  wfCompName = "MStatus"
  isRoute = {false}
  requestId ='1143246373753200645'
/>
```
>组件props参数说明

| 参数 | 说明 |类型| 是否必填 | 默认值 |
| ---- | ---- | ---- | ---- | ---- |
|wfCompName|组件名称|MStatus|是|-|
|requestId|	流程请求id，新建流程不支持展示|string|是|-|
|isRoute|是否路由模式加载|boolean|否|true|


# 四、前端二开案例

## 4.1、屏蔽指定流程移动端底部指定操作按钮
>需求：自定义屏蔽指定流程的底部操作按钮，可参考[链接](https://www.e-cology.com.cn/sp/doc/docShare/980919527907115117?tenantKey=t7akvdnf84)


![](/api/ecode/resource/view/${appRes}/1712568536-image.png)