流程设计前端数据结构
一、流程属性
1. 基础属性
参数名称 | 类型 | 说明 |
workflowCode | string | 流程编码 |
workflowName | string | 显示名称 |
2. 流程事件
参数名称 | 类型 | 说明 |
startEventHandler | ActivityEventHandler | null | 流程启动事件 |
endEventHandler | ActivityEventHandler | null | 流程结束事件 |
cancelEventHandler | ActivityEventHandler | null | 流程作废事件 |
activateEventHandler | ActivityEventHandler | null | 流程激活事件 |
ActivityEventHandler 类型
参数名称 | 类型 | 说明 |
bizActions | Array | 执行业务方法 |
content | string | 通知消息内容 |
dataDisposals | Array | 设置数据, |
popupType | string | 参与者函数弹窗类型(EXPRESSION:表达式视图,FUNCTION:公式视图) |
receiver | string | 钉钉消息通知方(参与者函数公式) |
cancelParllelActivity | boolean | 是否取消并行活动(节点特有) |
rejectCancelParllelActivity | boolean | 驳回是否取消并行活动(节点特有) |
二、节点属性(activity)
1. 一般属性
参数名称 | 类型 | 说明 |
activityCode | string | 编码 |
activityName | string | 显示名称 |
name_i18n | object | 显示名称国际化字段 |
activityType | string | 节点类型 |
sheetCode | string | 任务表单(传阅、用户活动特有) |
todoDataItem.dataItemType | number | 消息通知(用户活动特有) |
todoDataItem.summary | string | 自定义通知内容 |
todoDataItem.title | String | 自定义通知标题 |
sync | boolean | 子流程启动方式(子流程特有) |
workflowCode | string | 子流程模板(子流程特有) |
finishStartActivity | boolean | 发起环节是否自动提交(子流程特有) |
triggerMappingObj | object | 触发对象(子流程特有): |
2. 参与者
参数名称 | 类型 | 说明 |
participant | string | 参与者,(参与者函数公式) |
popupType | string | 参与者函数弹窗类型(EXPRESSION:表达式视图,FUNCTION:公式视图) |
participationModel | string | 参与者类型:多人 / 单人 |
noParticipant | string | 无参与者:转交管理员 / 直接通过 |
originator | string | 参与者是发起人,是否直接通过 |
perviousParticipate | string | 参与者在前一活动处理过,是否直接通过 |
participated | string | 参与者处理过流程,是否直接通过 |
3. 数据权限(propertyPermissions)
数据项权限 Item 元数据:
参数名称 | 类型 | 说明 |
propertyName | string | 数据项名称 |
propertyCode | string | 数据项编码 |
editable | boolean | 是否可写 |
visible | boolean | 是否可见 |
required | boolean | 是否必填 |
propertyEmpty | boolean | 是否允许为空 |
subPropertyPermissions | Array | 子表数据权限 |
4. 操作权限(permittedAction)
参数名称 | 类型 | 说明 |
forward | boolean | 是否允许转办 |
retrieve | boolean | 是否允许撤回 |
assist | boolean | 是否允许协办 |
circulate | boolean | 是否允许传阅 |
adjustParticipant | boolean | 是否允许加签 |
finishInstance | boolean | 是否直接结束流程 |
reject | boolean | 是否允许驳回到上一步 |
rejectToStart | boolean | 是否允许驳回到开始节点 |
rejectToFixded | boolean | 是否允许驳回到指定活动 |
rejectToActivityCode | string | 驳回到指定节点对应的节点编码 |
5. 高级
参数名称 | 类型 | 说明 |
allowedTime | string | 限时时间 |
timeoutWarning1 | string | 超时预警1 |
timeoutWarning2 | string | 超时预警2 |
timeoutStrategy | string | 超时策略 |
6. 事件处理
参数名称 | 类型 | 说明 |
beforeActivate | ActivityEventHandler | 活动激活前 |
afterActivate | ActivityEventHandler | 活动激活后 |
endActivity | ActivityEventHandler | 活动完成后 |
cancelActivity | ActivityEventHandler | 活动取消后 |
三、连接线属性(rules)
参数名称 | 类型 | 说明 |
text | string | null | 显示名称 |
name_i18n | string | 显示名称国际化:{"en":""} |
formula | string | 条件设置 |
popupType | string | 参与者函数弹窗类型(EXPRESSION:表达式视图,FUNCTION:公式视图) |
utilizeElse | boolean | 是否使用else |
preActivityCode | string | 接入节点编码 |
postActivityCode | string | 流出节点编码 |
points | Array | 线上折点:["x,y"],eg: ["406,76"] |
需求概述
流程设计中新增加节点"用户活动(密级)",该节点的属性栏中只显示四个属性,节点名称,节点编码,参与人与密级。流程运转到该节点进行参与人计算时,需要根据节点上的密级属性配置与计算出的参与人密级字段进行二次过滤。
(人员密级信息由人员拓展字段提供数据)
前端扩展说明
一、节点扩展配置
扩展路径:packages\extension-template\src\workflow-design\extension-activities.ts
节点配置示例
import { ActivityTypes } from 'cloudpivot-admin-core/src/common/workflow-schema/typings/enums'; /** * 扩展节点 */ interface ExtActivity { //节点中文名称 activityName: string; //节点类型(继承自) activityType: ActivityTypes; //扩展节点类型(节点根据节点类型定位属性栏配置时,优先取扩展节点类型,其次才是节点类型) extendActivityType: string; //后端要求扩展属性得放在节点对象的属性extAttributes对象中,这里定义extAttributes对象的属性初始值 extAttributes: any; // 节点图标,使用iconfont图标库,标识图标的unicode编码。如: // 云枢图标库demo文件地址:packages\builtin\cloudpivot-icons\src\demo_index.html;浏览器打开查看图标 icon?: string; // 节点名称多语言对象 name_i18n?: { en: string; }, } /** * 扩展节点数组 */ export const extActivities: ExtActivity[] = [ { activityName: '用户活动(密级)', activityType: ActivityTypes.User, extendActivityType: 'CustomNode', extAttributes: { securityLevel: '0', }, }, ];
ExtActivity扩展节点对象中的可选属性若不进行定义,则跟继承的系统节点类型保持一致,例如:icon、name_i18n
注:extendActivityType项目已经使用,相关字段需前后端同步修改
节点配置后运行效果
节点扩展配置完成后,会在流程设计左侧流程节点列表中增加一个扩展节点,此时还需要给节点配置相关属性
二、节点属性面板配置
扩展路径:packages\extension-template\src\workflow-design\attr-panel\extension-panel-example.ts
引用产品已定义属性
产品已定义的流程节点属性,可直接引用,例如:activityCode、activityName、participant等;
获取方式:attrPanelRegister.getAttr(节点类型, 属性code),例如:attrPanelRegister.getAttr(ActivityTypes.User, 'activityCode')
属性配置示例
import { PanelConfig } from 'cloudpivot-designer/property-panel'; import { attrPanelRegister } from 'cloudpivot-admin-core/src/components/apps/workflow-property/scripts'; import { ActivityTypes } from 'cloudpivot-admin-core/src/common/workflow-schema/typings/enums'; const panelExample: PanelConfig = { properties: [ attrPanelRegister.getAttr(ActivityTypes.User, 'activityCode'), attrPanelRegister.getAttr(ActivityTypes.User, 'activityName'), attrPanelRegister.getAttr(ActivityTypes.User, 'participant'), { title: '密级', code: 'securityLevel', //输入组件名称 inputComponentName: 'property-select', //输入组件的参数 options: { selectOptions: [ { label: '非密', value: '0' }, { label: '内部', value: '1' }, { label: '秘密', value: '2' }, { label: '机密', value: '3' }, { label: '绝密', value: '4' }, ], }, /** * 用户修改密级字段信息时,同步修改节点对象中扩展对象extAttributes下securityLevel属性的值 **/ valueMap: 'extAttributes.securityLevel', } ], }; export default panelExample;
三、节点属性面板注册
扩展路径:packages\extension-template\src\workflow-design\extension-attr-panel.ts
import { attrPanelRegister } from 'cloudpivot-admin-core/src/components/apps/workflow-property/scripts'; import panelExample from './attr-panel/extend-panel-example'; attrPanelRegister.append('CustomNode', panelExample);
注册后运行效果
后端扩展说明
扩展示例代码
public class ExtParticipantFilterServiceImpl implements ParticipantFilterService { // autowires private UserFacade userFacade; private UserExtendFacade userExtendFacade; @Override public Set<String> doFilter(Set<String> participants, ParticipantProcessorContext context) { if (CollectionUtils.isEmpty(participants)) { return participants; } ConfidentialLevel confidentialLevel = getConfidentialLevel(context); if (confidentialLevel == null || confidentialLevel == ConfidentialLevel.NON_CONFIDENTIAL) { return participants; } List<String> userIdList = Lists.newArrayList(participants); List<UserModel> userModels = userFacade.listByIdList(userIdList); if (CollectionUtils.isEmpty(userModels)) { return participants; } UserExtAttrModel confidentialLevelAttr = userExtendFacade.getExtAttrByCorpIdAndCode("RELEVANCE-6cf4718787374570a0c583f939077e77", "confidentialLevel"); if (confidentialLevelAttr == null) { return participants; } Set<String> filtered = Sets.newLinkedHashSet(); List<UserUnionExtAttrModel> extAttrs = userExtendFacade.listUnionByUserIdListAndAttrIdList(userIdList, Lists.newArrayList(confidentialLevelAttr.getId())); if (CollectionUtils.isEmpty(extAttrs)) { return filtered; } Map<String, List<UserUnionExtAttrModel>> userId2ExtAttrs = extAttrs.stream().collect(Collectors.groupingBy(UserUnionExtAttrModel::getUserId)); for (UserModel userModel : userModels) { List<UserUnionExtAttrModel> userExtAttrs = userId2ExtAttrs.get(userModel.getId()); if (CollectionUtils.isEmpty(userExtAttrs)) { continue; } if (userExtAttrs.stream().anyMatch(e -> { ConfidentialLevel level = ConfidentialLevel.get(e.getMapVal()); return level != null && level.getIndex() >= confidentialLevel.getIndex(); })) { filtered.add(userModel.getId()); } } return filtered; } private ConfidentialLevel getConfidentialLevel(ParticipantProcessorContext context) { Map<String, Object> extAttributes = context.getActivity().getExtAttributes(); if (MapUtils.isEmpty(extAttributes)) { return ConfidentialLevel.NON_CONFIDENTIAL; } String securityLevel = (String) extAttributes.get("securityLevel"); if (StringUtils.isBlank(securityLevel)) { return ConfidentialLevel.NON_CONFIDENTIAL; } return ConfidentialLevel.get(Integer.parseInt(securityLevel)); } public enum ConfidentialLevel { /** * 非密、内部、秘密、机密、绝密 */ NON_CONFIDENTIAL("非密", 0), INTERNAL("内部", 1), CONFIDENTIAL("秘密", 2), SECRET("机密", 3), TOP_SECRET("绝密", 4); private final String name; private final int index; ConfidentialLevel(String name, int index) { this.name = name; this.index = index; } public static ConfidentialLevel get(int index) { for (ConfidentialLevel level : values()) { if (level.index == index) { return level; } } return null; } public static ConfidentialLevel get(String name) { for (ConfidentialLevel level : values()) { if (StringUtils.equals(level.name, name)) { return level; } } return null; } // getters.. } }
二次开发效果截图
表单详情
用户配置
Q&A
使用到的二开扩展能力
前端流程设计-流程节点扩展开发说明文档
前端流程设计-流程节点属性栏配置扩展开发说明文档
后端流程运行参与人函数扩展
流程属性栏注册器API
方法名称 | 说明 | 参数说明 |
append(panelCode: string, panelConfig: PanelConfig) | 添加新的属性栏配置 | 属性栏code,属性栏配置 |
replace(panelCode: string, panelConfig: PanelConfig) | 替换现有的属性栏配置 | 属性栏code,属性栏配置 |
replaceAttr(panelCode: string, attrConfig: PropertySchema) | 替换现有属性栏中的某个属性 | 属性栏code,属性配置(包含属性的code) |
appendAttr(panelCode: string, attrConfig: PropertySchema, groupKey?: string) | 在现有属性栏中追加新属性,分组编码可选,如果不传入分组编码则在最后一个分组中添加 | 属性栏code, 属性配置,分组编码 |
appendGroup(panelCode: string, groupInfo: any) | 在现有属性栏中添加分组 | 属性栏code,分组信息 |
getAttr(panelCode: string, attrCode: string) | 获取现有的属性栏中,某个属性的具体配置 | 属性栏code, 属性code |
属性配置properties释义
interface PropertySchema { //属性标题,如果不设置则表示不需要显示标题 title?: string; //属性编码 code: string; /** * 输入组件值的映射,如果只是简单通过code取可以不设置,如果是多个属性合并的场景,需要配置 * 例如:code为a,b,c,valueMap为['a','b','c'],则输入组件的值为{a:1,b:2,c:3} **/ valueMap?: string[] | any; //属性提示 tips?: string; //输入组件名称 inputComponentName: string; // 自定义的判空逻辑,如果不设置则默认为!!value isNotEmpty?: (value: any) => boolean; // 自定义的必填提示文案,如果不设置走默认文案逻辑 getRequiredErrorMessage?: (controller, propertiesData) => string; // 必填以外的校验逻辑,校验后的提示文案 getValueValidateErrorMessage?: (controller, propertiesData) => string; //默认值函数 defaultValue?: (businessContext, propertiesData: any) => any; //弹窗组件是否需要显示删除确认弹窗 showDeleteConfirm?: boolean | ((value: any) => boolean | Promise<boolean>); //弹窗组件删除确认弹窗文案 confirmText?: string; //隐藏整个组件的判断函数,只支持简单场景,如果需要用到的数据在controller中,需要在subscription中处理 hiddenFunc?: (propertiesData: any) => boolean; //属性值传递给组件时进行的映射 inputValueTransform?: (value: any) => any; //组件值传递给属性时进行的映射 outputValueTransform?: (value: any) => any; //组件的参数props options?: any; }
更多属性输入组件
使用场景
流程现有流程节点有:传阅、用户活动、系统节点、连接点、子流程。客户想要在现有节点的基础上,简化节点的配置,隐藏部分属性配置,只配置客户需要的部分属性。需要注意的是,流程节点类型不会有增加,因此后端相关节点运行逻辑不需要调整。
扩展文件位置
packages\extension-template\src\workflow-design\extension-activities.ts
/** * 扩展节点数组 */ export const extendActivities = [ // { // activityName: '扩展节点', // name_i18n: { // en: 'Example Extend Node', // }, // width: 158, // height: 40, // icon: '', // activityType: 'CONNECTION', // extendActivityType: 'CustomNode', // }, ];
扩展规范
[ { activityName: '用户活动', name_i18n: { en: 'UserAction', }, width: 158, height: 40, icon: '', activityType: 'PARTICIPANT', }, { activityName: '系统活动', name_i18n: { en: 'BizAction', }, width: 158, height: 40, icon: '', activityType: 'SYSTEM_ACTIVITY', }, { activityName: '子流程', name_i18n: { en: 'SubInstance', }, width: 158, height: 40, icon: '', activityType: 'SUB_INSTANCE', }, { activityName: '连接点', name_i18n: { en: 'Connection', }, width: 158, height: 40, icon: '', activityType: 'CONNECTION', }, { activityName: '传阅', name_i18n: { en: 'Circularize', }, width: 158, height: 40, icon: '', activityType: 'CIRCULATE', }, ]
扩展的节点应该基于现有的节点配置,首先拷贝一份扩展自节点的配置(从用户活动扩展就复制用户活动的节点配置),然后修改节点的名称、图标、扩展节点类型
注意:activityType只能从现有的节点类型选取,不能设置新值。extendActivityType不能与现有的activityType重复。
示例
扩展节点配置
{ activityName: '示例扩展节点', name_i18n: { en: 'Example Extend Node', }, width: 158, height: 40, icon: '', activityType: 'CONNECTION', extendActivityType: 'CustomNode', }
使用场景
修改现有的流程属性,节点属性,连接线属性(删除属性可以通过修改已有属性的可见性实现)
在现有的流程属性,节点属性,连接线属性上追加属性
扩展流程节点后,整体定义扩展的流程节点属性栏的配置
扩展文件位置
packages\extension-template\src\workflow-design\extension-attr-panel.ts
属性栏配置参考
使用场景
在扩展流程属性栏时需要使用到新的属性输入组件时
扩展文件位置
packages\extension-template\src\workflow-design\extension-attr-input-component.ts
import { propertyRegister } from 'cloudpivot-designer/property-panel'; import PropertyComponentDemo from './extension-components/property-component-demo.vue'; import ModalComponentDemo from './extension-components//modal-components/modal-component-demo.vue'; propertyRegister.append('property-component-demo', PropertyComponentDemo); propertyRegister.append('modal-component-demo', ModalComponentDemo);
方法名称 | 说明 | 参数说明 |
append(panelCode: string, panelConfig: PanelConfig) | 添加新的属性栏配置 | 属性栏code,属性栏配置 |
replace(panelCode: string, panelConfig: PanelConfig) | 替换现有的属性栏配置 | 属性栏code,属性栏配置 |
replaceAttr(panelCode: string, attrConfig: PropertySchema) | 替换现有属性栏中的某个属性 | 属性栏code,属性配置(包含属性的code) |
appendAttr(panelCode: string, attrConfig: PropertySchema, groupKey?: string) | 在现有属性栏中追加新属性,分组编码可选,如果不传入分组编码则在最后一个分组中添加 | 属性栏code, 属性配置,分组编码 |
appendGroup(panelCode: string, groupInfo: any) | 在现有属性栏中添加分组 | 属性栏code,分组信息 |
getAttr(panelCode: string, attrCode: string) | 获取现有的属性栏中,某个属性的具体配置 | 属性栏code, 属性code |