# 一、场景描述
随着业务的增长某些客户需要向表单应用、流程基本信息、流程图注入一些个性化的参数。BPM针对表单应用详情页面、流程设计页面、流程图节点信息组件做了页签扩展能力。
# 1.1 用户查看页面或者组件页签时序图

# 1.2 页签接入
本文前端部分仅提供React示例。在开始之前,推荐先学习 React (opens new window),并正确安装和配置了 Node.js (opens new window) v16 或以上。官方指南假设你已了解关于 HTML、CSS 和 JavaScript 的中级知识,并且已经完全掌握了 React 全家桶的正确开发方式。当然并不代表只能用React扩展页签,你依然可以使用原生代码或者其他框架,你只需关注示例中的参数,并根据实际需要开发即可。
# 1.2.1 创建自定义页面
所有自定义页面需要发布到服务器上。针对不同场景的自定义页签,BPM在加载自定义页面时会根据当前场景传递一些必要的参数,这些参数将拼接在url上。
# 场景1、表单应用详情
加载页面时URL上会传递应用guid(guid)、应用id(appId)、应用来源标识(artifactSource)。

前端示例代码:
import React, { useRef } from 'react';
/**
* 获取query参数
* @param variable -string
* @returns -string | undefined
*/
const getQueryParam = (variable: string) => {
const query = window.location.search.substring(1);
const vars = query.split('&');
for (let i = 0; i < vars.length; i++) {
const pair = vars[i].split('=');
if (pair[0] === variable) {
return pair[1];
}
}
return undefined;
};
const AppDeatilCustomTab = () => {
//应用guid
const guid = getQueryParam('guid');
//应用id
const appId = getQueryParam('appId');
//应用来源标识。DEFAULT:标识应用是当前环境设计的;MAVEN或者OSS:表示跨环境推送到本环境的
const artifactSource = getQueryParam('artifactSource');
const inputRef = useRef<HTMLInputElement | null>(null);
//提交
const onSubmit = () => {
const value = inputRef.current?.value;
console.log(guid, appId, artifactSource, value);
};
//渲染页面组件
return (
<div style={{ margin: 20 }}>
<div style={{ display: 'flex' }}>
<div>自定义参数:</div>
<div>
<input ref={inputRef} style={{ border: '1px solid #ccc', borderRadius: '4px' }} />
</div>
</div>
<div style={{ marginTop: 10 }}>
<button
style={{
background: '#1890ff',
padding: '4px 8px',
border: 'none',
color: '#fff',
borderRadius: '4px',
}}
onClick={onSubmit}>
提交
</button>
</div>
</div>
);
};
export default AppDeatilCustomTab;
# 场景2、流程设计
加载页面时URL上会传递应用guid(guid)、应用id(appId)、模板id(templateId)

示例代码:
import React, { useRef } from 'react';
/**
* 获取query参数
* @param variable -string
* @returns -string | undefined
*/
const getQueryParam = (variable: string) => {
const query = window.location.search.substring(1);
const vars = query.split('&');
for (let i = 0; i < vars.length; i++) {
const pair = vars[i].split('=');
if (pair[0] === variable) {
return pair[1];
}
}
return undefined;
};
const ProcessDesignCustomTab = () => {
//应用guid
const guid = getQueryParam('guid');
//应用id
const appId = getQueryParam('appId');
//模板id
const templateId = getQueryParam('templateId');
const inputRef = useRef<HTMLInputElement | null>(null);
//提交
const onSubmit = () => {
const value = inputRef.current?.value;
console.log(guid, appId, templateId, value);
};
return (
<div style={{ margin: 20 }}>
<div style={{ display: 'flex' }}>
<div>自定义参数:</div>
<div>
<input ref={inputRef} style={{ border: '1px solid #ccc', borderRadius: '4px' }} />
</div>
</div>
<div style={{ marginTop: 10 }}>
<button
style={{
background: '#1890ff',
padding: '4px 8px',
border: 'none',
color: '#fff',
borderRadius: '4px',
}}
onClick={onSubmit}>
提交
</button>
</div>
</div>
);
};
export default ProcessDesignCustomTab;
# 场景3、节点属性
加载页面时URL会传递应用id(appId),模板id(templateId),节点id(activityId)。自定义页签保存的值只能是字符串,保存的值将赋给节点的extProp属性。

事件消息体data部分:通过type区分事件类型,value传递属性值。
type类型:
GET_CUSTOM_VALUE_${appId}_${templateId}_${activityId}:向父窗口询问节点的扩展属性(extProp)值;
SEND_CUSTOM_VALUE_${appId}_${templateId}_${activityId}:父窗口发送扩展属性(extProp)值;
CHANGE_VALUE_${appId}_${templateId}_${activityId}:向父窗口提交扩展属性(extProp)值;
1、如果需要获取当前节点扩展属性(extProp)值,需要先通过postMessage主动发起 GET_CUSTOM_VALUE_${appId}_${templateId}_${activityId}事件,并且监听SEND_CUSTOM_VALUE_${appId}_${templateId}_${activityId}事件,该事件传递的value即为扩展属性值。
2、当自定义属性需要保存到当前节点时通过postMessage发起CHANGE_VALUE_${appId}_${templateId}_${activityId}事件,且通过value传递扩展属性值。
示例代码:
import React, { useEffect } from 'react';
import { Button, Form, Input } from '@seeyon/ui';
/**
* 获取query参数
* @param variable -string
* @returns -string | undefined
*/
const getQueryParam = (variable: string) => {
const query = window.location.search.substring(1);
const vars = query.split('&');
for (let i = 0; i < vars.length; i++) {
const pair = vars[i].split('=');
if (pair[0] === variable) {
return pair[1];
}
}
return undefined;
};
const ThirdNodeProps = () => {
const [form] = Form.useForm();
//iframe的scr- url的query包含应用id,模板id,节点id
const appId = getQueryParam('appId');
const templateId = getQueryParam('templateId');
const activityId = getQueryParam('activityId');
//监听上层传递的值-字符串
useEffect(() => {
//主动发消息获取当前页面的值:`GET_CUSTOM_VALUE_${appId}_${templateId}_${activityId}`
window.parent.postMessage({ type: `GET_CUSTOM_VALUE_${appId}_${templateId}_${activityId}` }, '*');
//接收父窗口传递下来的值:`SEND_CUSTOM_VALUE_${appId}_${templateId}_${activityId}`
window.parent.addEventListener(`message`, (data: any) => {
const { type, value } = data.data || {};
if (type === `SEND_CUSTOM_VALUE_${appId}_${templateId}_${activityId}`) {
try {
const values = JSON.parse(value);
form.setFieldsValue(values);
} catch (error) {
console.log(error);
}
}
});
}, []);
//调用postMessage,主动提交数据:`CHANGE_VALUE_${appId}_${templateId}_${activityId}`
const onFinish = (values: any) => {
window.parent.postMessage(
{
type: `CHANGE_VALUE_${appId}_${templateId}_${activityId}`,
value: JSON.stringify(values),
},
'*',
);
};
return (
<div>
<div>三方注册的节点属性页签</div>
<Form labelCol={{ span: 5 }} wrapperCol={{ span: 18 }} form={form} onFinish={onFinish}>
<Form.Item key={'customProperty'} name={'customProperty'} label="自定义属性">
<Input maxLenth={50}></Input>
</Form.Item>
</Form>
<div>
<Button type="primary" onClick={form.submit}>
iframe提交
</Button>
</div>
</div>
);
};
export default ThirdNodeProps;
** 注: 1、前端准备好页面后需要发布到服务器。确保页面能够在浏览器中正常访问。 2、场景1、场景2需要通过客开自行调用后端接口方式保存数据,详情见:1.2.4.1 **
# 1.2.2 注册前端页签
每个页签都需要唯一的key(tabKey),标品提供的页签我们称之为默认页签。表单应用详情和流程设计默认页签对应的key如下,新增页签时需要避免与默认页签重复。其中流程图节点属性的页签顺序不会根据sort更改,流程图节点属性的默认页签只会是最后一个页签。tabSubGroup是默认页签的二级分类,流程设计和流程图节点属性都有二级分类。
# 1、默认页签
默认页签间隔10个单位,与插入的页签共同排序(sort),业务方需自行控制插入页签的顺序。
前端定义如下:
export const defaultTabs: { [key: string]: IBpmCustomTab[] } = {
//表单应用详情默认页签
APP_APPROVAL_DETAIL: [
{ tabKey: 'base_info', sort: 10 }, //基本信息
{ tabKey: 'design_publish', sort: 20 }, //设计发布
{ tabKey: 'process_empower', sort: 30 }, //流程权限
{ tabKey: 'base_data', sort: 40 }, //基础数据
{ tabKey: 'query_data', sort: 50 }, //数据查询
{ tabKey: 'process_authority', sort: 60 }, //节点权限
{ tabKey: 'app_log', sort: 70 }, //应用日志
],
//流程设计默认页签(tabSubGroup:TEMPLATE 表示流程模板信息,tabSubGroup:CONFIGURATION 表示流程配置信息)
PROCESS_DESIGN: [
{ tabKey: 'basic-info', sort: 10, tabSubGroup: 'TEMPLATE' }, //基本信息
{ tabKey: 'design', sort: 20, tabSubGroup: 'TEMPLATE' }, //流程设计
{ tabKey: 'form-permission', sort: 30, tabSubGroup: 'TEMPLATE' }, //操作权限
{ tabKey: 'third-form-param', sort: 40, tabSubGroup: 'TEMPLATE' }, //流程参数
{ tabKey: 'path', sort: 50, tabSubGroup: 'TEMPLATE' }, //流程路径表
{ tabKey: 'advanced-setting', sort: 60, tabSubGroup: 'TEMPLATE' }, //高级设置
//流程配置
{
tabKey: 'MENU_flowPathTable',
sort: 10,
tabSubGroup: 'CONFIGURATION',
tabTitle: '流程路径表',
}, //流程路径表
{ tabKey: 'MENU_FormAuth', sort: 20, tabSubGroup: 'CONFIGURATION', tabTitle: '表单权限' }, //表单权限
{
tabKey: 'MENU_CustomOperation',
sort: 30,
tabSubGroup: 'CONFIGURATION',
tabTitle: '自定义操作',
}, //自定义操作
],
};
# 2、 默认页签子分类(tabSubGroup)
1、流程设计二级分类:
| 节点类型 | 备注 |
|---|---|
| TEMPLATE | 流程模板信息 |
| CONFIGURATION | 流程配置信息 |
2、流程图节点属性按照节点类型做二级分类:
| 节点类型 | 备注 |
|---|---|
| 开始节点(BPM_START) 自动开始(BPM_AUTO_START) 定时开始(BPM_TIMER_START) | 开始节点 |
| 定时节点(BPM_TIMER) 监听节点(BPM_MONITOR) 事件节点(BPM_EVENT) 结束节点(BPM_END) 终止节点(BPM_STOP) | - |
| 条件网关节点(BPM_SPLIT) 汇聚网关节点(BPM_JOIN) | 条件网关节点 |
| 子流程(BPM_SUBPROCESS) 送转子流程(BPM_SUBPROCESS) | 子流程节点 |
| 自动节点(BPM_AUTO_ACTIVITY) 消息节点(BPM_MESSAGE_ACTIVITY) | - |
| 普通人工节点(bpmHumanActivity) 规则节点(humanRuleActivity) 脚本找人节点(scriptHumanActivity) 知会节点(bpmInfoActivity) 流程路径表(pathTableActivity) 逐级审批(levelapproval) 动态节点虚线框(bpmDynamicActivity) 动态节点(首节点)(bpmDynamicFirstActivity) 专人送转(transferPersonal) 共享服务节点(FSSCActivity) | 人工类型节点 |
# 3、自定义页签内容描述(tabContent)
前端定义如下:
{
type: 'iframe' | 'remoteComponent'; //客开系统仅支持iframe
url?: string; //iframe对应的源地址, 在原始URL上会拼接特定参数,如应用id,模板id等;
iframeStyle?: CSSProperties; //iframe样式
iframeClassName?: string; //iframe类名
remoteComponent?: any; // 页签内容支持模块联邦(入参请参考模块联邦组件的入参);
};
# 1.2.3 创建后端接入数据
# 1.2.3.1 后端数据定义
不同注册业务场景tabGroup字段值不一样。
| 字段名称 | 字段类型 | 备注 |
|---|---|---|
| applicationGuid | BIGINT | 应用guid |
| applicationName | VARCHAR(128) | 应用的name |
| tabKey | VARCHAR(50) | 页签的唯一标识(customType是insert时,tabKey一定不能重复) |
| tabTitle | VARCHAR(50) | 如果没有传入该字段,如果key是默认页签,展示默认标题,否则展示tabKey |
| tabContent | LONGTEXT | 自定义页签渲染需要的数据(参照前端数据类型定义) |
| customType | VARCHAR(50) | 自定义类型:insert(追加插入) |
| tabGroup | SMALLINT(6) | 页签分组 APP_APPROVAL_DETAIL:审批应用详情页面;PROCESS_DESIGN:流程设计页面;PROCESS_DIAGRAM_NODE:流程图节点属性 |
| tabSubGroup | VARCHAR(2000) | 页签分组子分类 |
| sort | INT | 排序 |
| enable | TINYINT | 是否启用 |
# 1.2.3.2 注册机制
1、如基于V8平台开发的客开应用,则注册使用平台提供的datainit机制 在 bpm@com.seeyon.bpm.domain.entity.BpmCustomTab.json中注册 需要预置json. 例:
[
{
applicationGuid: "-6319207780276483080",
applicationName: "dynamic4560675929256379644",
tabGroup: "PROCESS_DIAGRAM_NODE",
enable: true,
tabKey: "customTabIframe",
tabTitle: "自定义节点属性",
customType: "insert",
sort: 10,
tabSubGroup: "bpmHumanActivity,humanRuleActivity,scriptHumanActivity,bpmInfoActivity,pathTableActivity,levelapproval,bpmDynamicActivity,bpmDynamicFirstActivity,transferPersonal,FSSCActivity",
tabContent: "{\"type\":\"iframe\",\"iframeStyle\":{\"height\":500,\"width\":\"100%\",\"border\":\"none\"},\"url\":\"https://dev.seeyonv8.com/main/child-frame/bpm/node/thirdCustomTab\"}",
},
]
2、非V8平台的开发,联系技术提供注册方式。
# 1.2.4 运行态使用
# 1.2.4.1 更新模板的扩展信息
接口名称:更新模板的扩展信息 1、请求地址:/bpm/template/update-template-extend 2、参数名称
| 字段名称 | 字段类型 | 备注 |
|---|---|---|
| id | BIGINT | id |
| appBusinessData | string | 应用业务扩展数据 |
# 1.2.4.2 节点属性数据获取方式
接口名称:根据流程模板查询节点信息 1、请求地址:bpm/template-node/list 2、参数名称
| 字段名称 | 字段类型 | 备注 |
|---|---|---|
| templateGuid | BIGINT | 模板guid和模板id必须填写一个 |
| designState | enum | 和templateGuid一起使用,默认查运行态启用的模板。枚举项可选值列表:NONE(默认值:空),DESIGN(设计态),RUNTIME(运行态) |
| templateId | BIGINT | 有值优先根据模板id查 |
| activityType | enum | 节点类型。枚举项可选值列表:NONE(默认值:空),BPM_AND_ROUTER(网关节点),BPM_END(结束节点),BPM_AUTO_ACTIVITY(自动节点),BPM_HUMEN_ACTIVITY(人工节点),BPM_START(开始节点),BPM_STOP(终止节点),BPM_SUBPROCESS(子流程节点),BPM_AUTO_START(自动开始节点),BPM_TIMER_START(定时开始节点),BPM_EVENT_ACTIVITY(事件节点),BPM_TIMER_ACTIVITY(定时器节点),BPM_MESSAGE_ACTIVITY(消息节点),BPM_MONITOR_ACTIVITY(监听节点),BPM_DYNAMIC_ACTIVITY(动态节点),BPM_DYNAMIC_FIRST_ACTIVITY(动态首节点),BPM_NESTED_SUB_PROCESS_ACTIVITY(嵌套子流程节点),BPM_INFORM_ACTIVITY(知会节点),BPM_RULE_ACTIVITY(规则节点),BPM_PATH_TABLE(路径表节点),BPM_LEVEL_APPROVAL(逐级审批节点),BPM_SCRIPT_HUMAN(脚本找人节点),BPM_FSSC_HUMAN(共享节点) |
3、返回体
| 字段名称 | 字段类型 | 备注 |
|---|---|---|
| extProp | string | 节点中三方扩展信息 |
# 二、业务扩展
# 1、 机构级页签注册
注册数据中applicationGuid、applicationName为null时,则会注册成为机构下全局应用的注册数据
快速跳转