111 changed files with 7636 additions and 9191 deletions
@ -0,0 +1,12 @@ |
|||
package com.ruoyi.flowable.common.expand.el; |
|||
|
|||
/** |
|||
* 扩展表达式 |
|||
* |
|||
* @author Tony |
|||
* @date 2023-03-04 09:10 |
|||
*/ |
|||
public interface BaseEl { |
|||
|
|||
} |
|||
|
|||
@ -0,0 +1,32 @@ |
|||
package com.ruoyi.flowable.common.expand.el; |
|||
|
|||
import com.ruoyi.system.service.ISysDeptService; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
import javax.annotation.Resource; |
|||
|
|||
/** |
|||
* 扩展表达式 |
|||
* |
|||
* @author Tony |
|||
* @date 2023-03-04 12:10 |
|||
*/ |
|||
@Component |
|||
@Slf4j |
|||
public class FlowEl implements BaseEl { |
|||
|
|||
@Resource |
|||
private ISysDeptService sysDeptService; |
|||
|
|||
public String findDeptLeader(String name){ |
|||
log.info("开始查询表达式变量值,getName"); |
|||
return name; |
|||
} |
|||
|
|||
public String getName(String name){ |
|||
log.info("开始查询表达式变量值,getName"); |
|||
return name; |
|||
} |
|||
} |
|||
|
|||
@ -1,62 +0,0 @@ |
|||
package com.ruoyi.flowable.service; |
|||
|
|||
import com.ruoyi.system.domain.SysTaskForm; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 流程任务关联单Service接口 |
|||
* |
|||
* @author Tony |
|||
* @date 2021-04-03 |
|||
*/ |
|||
@Deprecated |
|||
public interface ISysTaskFormService { |
|||
/** |
|||
* 查询流程任务关联单 |
|||
* |
|||
* @param id 流程任务关联单ID |
|||
* @return 流程任务关联单 |
|||
*/ |
|||
public SysTaskForm selectSysTaskFormById(Long id); |
|||
|
|||
/** |
|||
* 查询流程任务关联单列表 |
|||
* |
|||
* @param sysTaskForm 流程任务关联单 |
|||
* @return 流程任务关联单集合 |
|||
*/ |
|||
public List<SysTaskForm> selectSysTaskFormList(SysTaskForm sysTaskForm); |
|||
|
|||
/** |
|||
* 新增流程任务关联单 |
|||
* |
|||
* @param sysTaskForm 流程任务关联单 |
|||
* @return 结果 |
|||
*/ |
|||
public int insertSysTaskForm(SysTaskForm sysTaskForm); |
|||
|
|||
/** |
|||
* 修改流程任务关联单 |
|||
* |
|||
* @param sysTaskForm 流程任务关联单 |
|||
* @return 结果 |
|||
*/ |
|||
public int updateSysTaskForm(SysTaskForm sysTaskForm); |
|||
|
|||
/** |
|||
* 批量删除流程任务关联单 |
|||
* |
|||
* @param ids 需要删除的流程任务关联单ID |
|||
* @return 结果 |
|||
*/ |
|||
public int deleteSysTaskFormByIds(Long[] ids); |
|||
|
|||
/** |
|||
* 删除流程任务关联单信息 |
|||
* |
|||
* @param id 流程任务关联单ID |
|||
* @return 结果 |
|||
*/ |
|||
public int deleteSysTaskFormById(Long id); |
|||
} |
|||
@ -1,93 +0,0 @@ |
|||
package com.ruoyi.flowable.service.impl; |
|||
|
|||
import java.util.List; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.stereotype.Service; |
|||
import com.ruoyi.system.mapper.SysTaskFormMapper; |
|||
import com.ruoyi.system.domain.SysTaskForm; |
|||
import com.ruoyi.flowable.service.ISysTaskFormService; |
|||
|
|||
/** |
|||
* 流程任务关联单Service业务层处理 |
|||
* |
|||
* @author Tony |
|||
* @date 2021-04-03 |
|||
*/ |
|||
@Service |
|||
public class SysTaskFormServiceImpl implements ISysTaskFormService |
|||
{ |
|||
@Autowired |
|||
private SysTaskFormMapper sysTaskFormMapper; |
|||
|
|||
/** |
|||
* 查询流程任务关联单 |
|||
* |
|||
* @param id 流程任务关联单ID |
|||
* @return 流程任务关联单 |
|||
*/ |
|||
@Override |
|||
public SysTaskForm selectSysTaskFormById(Long id) |
|||
{ |
|||
return sysTaskFormMapper.selectSysTaskFormById(id); |
|||
} |
|||
|
|||
/** |
|||
* 查询流程任务关联单列表 |
|||
* |
|||
* @param sysTaskForm 流程任务关联单 |
|||
* @return 流程任务关联单 |
|||
*/ |
|||
@Override |
|||
public List<SysTaskForm> selectSysTaskFormList(SysTaskForm sysTaskForm) |
|||
{ |
|||
return sysTaskFormMapper.selectSysTaskFormList(sysTaskForm); |
|||
} |
|||
|
|||
/** |
|||
* 新增流程任务关联单 |
|||
* |
|||
* @param sysTaskForm 流程任务关联单 |
|||
* @return 结果 |
|||
*/ |
|||
@Override |
|||
public int insertSysTaskForm(SysTaskForm sysTaskForm) |
|||
{ |
|||
return sysTaskFormMapper.insertSysTaskForm(sysTaskForm); |
|||
} |
|||
|
|||
/** |
|||
* 修改流程任务关联单 |
|||
* |
|||
* @param sysTaskForm 流程任务关联单 |
|||
* @return 结果 |
|||
*/ |
|||
@Override |
|||
public int updateSysTaskForm(SysTaskForm sysTaskForm) |
|||
{ |
|||
return sysTaskFormMapper.updateSysTaskForm(sysTaskForm); |
|||
} |
|||
|
|||
/** |
|||
* 批量删除流程任务关联单 |
|||
* |
|||
* @param ids 需要删除的流程任务关联单ID |
|||
* @return 结果 |
|||
*/ |
|||
@Override |
|||
public int deleteSysTaskFormByIds(Long[] ids) |
|||
{ |
|||
return sysTaskFormMapper.deleteSysTaskFormByIds(ids); |
|||
} |
|||
|
|||
/** |
|||
* 删除流程任务关联单信息 |
|||
* |
|||
* @param id 流程任务关联单ID |
|||
* @return 结果 |
|||
*/ |
|||
@Override |
|||
public int deleteSysTaskFormById(Long id) |
|||
{ |
|||
return sysTaskFormMapper.deleteSysTaskFormById(id); |
|||
} |
|||
} |
|||
@ -0,0 +1,44 @@ |
|||
import request from '@/utils/request' |
|||
|
|||
// 查询流程达式列表
|
|||
export function listExpression(query) { |
|||
return request({ |
|||
url: '/system/expression/list', |
|||
method: 'get', |
|||
params: query |
|||
}) |
|||
} |
|||
|
|||
// 查询流程达式详细
|
|||
export function getExpression(id) { |
|||
return request({ |
|||
url: '/system/expression/' + id, |
|||
method: 'get' |
|||
}) |
|||
} |
|||
|
|||
// 新增流程达式
|
|||
export function addExpression(data) { |
|||
return request({ |
|||
url: '/system/expression', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
|
|||
// 修改流程达式
|
|||
export function updateExpression(data) { |
|||
return request({ |
|||
url: '/system/expression', |
|||
method: 'put', |
|||
data: data |
|||
}) |
|||
} |
|||
|
|||
// 删除流程达式
|
|||
export function delExpression(id) { |
|||
return request({ |
|||
url: '/system/expression/' + id, |
|||
method: 'delete' |
|||
}) |
|||
} |
|||
@ -0,0 +1,44 @@ |
|||
import request from '@/utils/request' |
|||
|
|||
// 查询流程监听列表
|
|||
export function listListener(query) { |
|||
return request({ |
|||
url: '/system/listener/list', |
|||
method: 'get', |
|||
params: query |
|||
}) |
|||
} |
|||
|
|||
// 查询流程监听详细
|
|||
export function getListener(id) { |
|||
return request({ |
|||
url: '/system/listener/' + id, |
|||
method: 'get' |
|||
}) |
|||
} |
|||
|
|||
// 新增流程监听
|
|||
export function addListener(data) { |
|||
return request({ |
|||
url: '/system/listener', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
|
|||
// 修改流程监听
|
|||
export function updateListener(data) { |
|||
return request({ |
|||
url: '/system/listener', |
|||
method: 'put', |
|||
data: data |
|||
}) |
|||
} |
|||
|
|||
// 删除流程监听
|
|||
export function delListener(id) { |
|||
return request({ |
|||
url: '/system/listener/' + id, |
|||
method: 'delete' |
|||
}) |
|||
} |
|||
@ -1,9 +0,0 @@ |
|||
{ |
|||
"extends": [ |
|||
"bpmnlint:recommended", |
|||
"plugin:local/recommended" |
|||
], |
|||
"rules": { |
|||
"local/no-manual-task": "warn" |
|||
} |
|||
} |
|||
@ -1,68 +0,0 @@ |
|||
/** |
|||
* 存储流程设计相关参数 |
|||
*/ |
|||
export default class BpmData { |
|||
constructor() { |
|||
this.controls = [] // 设计器控件
|
|||
this.init() |
|||
} |
|||
|
|||
init() { |
|||
this.controls = [ |
|||
{ |
|||
action: 'create.start-event', |
|||
title: '开始' |
|||
}, |
|||
{ |
|||
action: 'create.intermediate-event', |
|||
title: '中间' |
|||
}, |
|||
{ |
|||
action: 'create.end-event', |
|||
title: '结束' |
|||
}, |
|||
{ |
|||
action: 'create.exclusive-gateway', |
|||
title: '网关' |
|||
}, |
|||
{ |
|||
action: 'create.task', |
|||
title: '任务' |
|||
}, |
|||
{ |
|||
action: 'create.user-task', |
|||
title: '用户任务' |
|||
}, |
|||
{ |
|||
action: 'create.user-sign-task', |
|||
title: '会签任务' |
|||
}, |
|||
{ |
|||
action: 'create.subprocess-expanded', |
|||
title: '子流程' |
|||
}, |
|||
{ |
|||
action: 'create.data-object', |
|||
title: '数据对象' |
|||
}, |
|||
{ |
|||
action: 'create.data-store', |
|||
title: '数据存储' |
|||
}, |
|||
{ |
|||
action: 'create.participant-expanded', |
|||
title: '扩展流程' |
|||
}, |
|||
{ |
|||
action: 'create.group', |
|||
title: '分组' |
|||
} |
|||
] |
|||
} |
|||
|
|||
// 获取控件配置信息
|
|||
getControl(action) { |
|||
const result = this.controls.filter(item => item.action === action) |
|||
return result[0] || {} |
|||
} |
|||
} |
|||
@ -1,168 +0,0 @@ |
|||
<template> |
|||
<div ref="propertyPanel" class="property-panel"> |
|||
<div v-if="nodeName" class="node-name">{{ nodeName }}</div> |
|||
<component |
|||
:is="getComponent" |
|||
v-if="element" |
|||
:element="element" |
|||
:modeler="modeler" |
|||
:users="users" |
|||
:groups="groups" |
|||
:exps="exps" |
|||
:categorys="categorys" |
|||
/> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import taskPanel from './components/nodePanel/task' |
|||
import startEndPanel from './components/nodePanel/startEnd' |
|||
import processPanel from './components/nodePanel/process' |
|||
import sequenceFlowPanel from './components/nodePanel/sequenceFlow' |
|||
import gatewayPanel from './components/nodePanel/gateway' |
|||
import { NodeName } from './lang/zh' |
|||
|
|||
export default { |
|||
name: 'PropertyPanel', |
|||
components: { processPanel, taskPanel, startEndPanel, sequenceFlowPanel, gatewayPanel }, |
|||
props: { |
|||
users: { |
|||
type: Array, |
|||
required: true |
|||
}, |
|||
groups: { |
|||
type: Array, |
|||
required: true |
|||
}, |
|||
categorys: { |
|||
type: Array, |
|||
required: true |
|||
}, |
|||
exps: { |
|||
type: Array, |
|||
default: () => [] |
|||
}, |
|||
modeler: { |
|||
type: Object, |
|||
required: true |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
element: null, |
|||
form: { |
|||
id: '', |
|||
name: '', |
|||
color: null |
|||
}, |
|||
} |
|||
}, |
|||
computed: { |
|||
getComponent() { |
|||
const type = this.element?.type |
|||
if (['bpmn:IntermediateThrowEvent', 'bpmn:StartEvent', 'bpmn:EndEvent'].includes(type)) { |
|||
return 'startEndPanel' |
|||
} |
|||
if ([ |
|||
'bpmn:UserTask', |
|||
'bpmn:Task', |
|||
'bpmn:SendTask', |
|||
'bpmn:ReceiveTask', |
|||
'bpmn:ManualTask', |
|||
'bpmn:BusinessRuleTask', |
|||
'bpmn:ServiceTask', |
|||
'bpmn:ScriptTask' |
|||
// 'bpmn:CallActivity', |
|||
// 'bpmn:SubProcess' |
|||
].includes(type)) { |
|||
return 'taskPanel' |
|||
} |
|||
if (type === 'bpmn:SequenceFlow') { |
|||
return 'sequenceFlowPanel' |
|||
} |
|||
if ([ |
|||
'bpmn:InclusiveGateway', |
|||
'bpmn:ExclusiveGateway', |
|||
'bpmn:ParallelGateway', |
|||
'bpmn:EventBasedGateway' |
|||
].includes(type)) { |
|||
return 'gatewayPanel' |
|||
} |
|||
if (type === 'bpmn:Process') { |
|||
return 'processPanel' |
|||
} |
|||
return null |
|||
}, |
|||
nodeName() { |
|||
if (this.element) { |
|||
const bizObj = this.element.businessObject |
|||
const type = bizObj?.eventDefinitions |
|||
? bizObj.eventDefinitions[0].$type |
|||
: bizObj.$type |
|||
return NodeName[type] || type |
|||
} |
|||
return '' |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.handleModeler() |
|||
}, |
|||
methods: { |
|||
handleModeler() { |
|||
this.modeler.on('root.added', e => { |
|||
if (e.element.type === 'bpmn:Process') { |
|||
this.element = null |
|||
this.$nextTick().then(() => { |
|||
this.element = e.element |
|||
}) |
|||
} |
|||
}) |
|||
this.modeler.on('element.click', e => { |
|||
const { element } = e |
|||
if (element.type === 'bpmn:Process' |
|||
|| element.type === 'bpmn:SequenceFlow' |
|||
|| element.type === 'bpmn:EndEvent' ) { |
|||
this.$nextTick().then(() => { |
|||
this.element = element |
|||
}) |
|||
} |
|||
}) |
|||
this.modeler.on('selection.changed', e => { |
|||
// hack 同类型面板不刷新 |
|||
this.element = null |
|||
const element = e.newSelection[0] |
|||
if (element) { |
|||
this.$nextTick().then(() => { |
|||
this.element = element |
|||
}) |
|||
} |
|||
}) |
|||
}, |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss"> |
|||
.property-panel { |
|||
padding: 20px 20px; |
|||
// reset element css |
|||
.el-form--label-top .el-form-item__label { |
|||
padding: 0; |
|||
} |
|||
// 设置设计器右侧表单高度 |
|||
.el-form-item { |
|||
margin-bottom: 6px; |
|||
} |
|||
.tab-table .el-form-item { |
|||
margin-bottom: 16px; |
|||
} |
|||
.node-name{ |
|||
border-bottom: 1px solid #ccc; |
|||
padding: 0 0 10px 20px; |
|||
margin-bottom: 10px; |
|||
font-size: 16px; |
|||
font-weight: bold; |
|||
color: #444; |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,181 @@ |
|||
|
|||
## 界面布局结构 |
|||
- palette(工具栏) :提供拖拽工具、框选工具、连线工具、基本图元等 |
|||
- contextPad(上下文面板):可以理解为快捷面板 |
|||
- propertiesPanel(属性面板):定义流程图中图形元素属性 |
|||
- shape(图形) 是所有图形的基类(比如Connection,Root) |
|||
|
|||
## 导入与导出 |
|||
```` |
|||
## 导入 |
|||
// 异步方式(推荐) |
|||
let result = await bpmnModeler.importXML(xml) |
|||
|
|||
// 回调方式 |
|||
bpmnModeler.importXML(xml, (result) => {} ) |
|||
|
|||
### 导出xml |
|||
// 异步方式 |
|||
let { xml } = await bpmnModeler.saveXML() |
|||
|
|||
// 回调方式 |
|||
bpmnModeler.saveXML({ format: false },({ xml }) => {}) |
|||
|
|||
// 格式化导出的xml |
|||
let { xml } = await bpmnModeler.saveXML({ format: true }) |
|||
|
|||
### 导出svg |
|||
// 异步方式 |
|||
let { svg } = await bpmnModeler.saveSVG() |
|||
|
|||
// 回调方式 |
|||
bpmnModeler.saveXML(( { svg } )=>{ }) |
|||
|
|||
## 导入的生命周期事件如下: |
|||
import.parse.start (即将从xml读取模型) |
|||
import.parse.complete (模型读取完成) |
|||
import.render.start (图形导入开始) |
|||
import.render.complete (图形导入完成) |
|||
import.done (一切都完成) |
|||
|
|||
```` |
|||
|
|||
## 内部模块/供应商/服务 |
|||
|
|||
- eventBus - 事件总线,管理bpmn实例中所有事件 |
|||
- canvas - 画布,管理svg元素、连线/图形的添加/删除、缩放等 |
|||
- commandStack - 命令堆栈,管理bpmn内部所有命令操作,提供撤销、重做功能等 |
|||
- elementRegistry - 元素注册表,管理bpmn内部所有元素 |
|||
- moddle - 模型管理,用于管理bpmn的xml结构 |
|||
- modeling - 建模器,绘图时用到,提供用于更新画布上元素的 API(移动、删除) |
|||
|
|||
```` |
|||
## 获取一个模块 |
|||
|
|||
// 第一个参数为模块名称,第二参数表示是否严格模式 |
|||
bpmnModeler.get("模块名称",false) |
|||
|
|||
```` |
|||
|
|||
## 事件总线 - eventBus |
|||
```` |
|||
## 获取事件总线模块 |
|||
let eventBus = bpmnModeler.get("eventBus") |
|||
|
|||
## 监听事件 |
|||
// 监听事件 |
|||
eventBus.on('element.changed', (ev) => {}) |
|||
|
|||
// 监听多个事件 |
|||
eventBus.on( |
|||
['shape.added', 'connection.added', 'shape.removed', 'connection.removed'], |
|||
(ev) => { |
|||
} |
|||
) |
|||
|
|||
// 设置优先级 |
|||
eventBus.on('element.changed', 100, (ev) => {}) |
|||
|
|||
// 传入上下文 |
|||
eventBus.on('element.changed', (ev) => {}, that) |
|||
|
|||
// 使用所有参数 |
|||
eventBus.on('事件名称', 优先级(可选), 回调函数, 上下文(可选)) |
|||
|
|||
## 只监听一次事件 |
|||
|
|||
// 用法同on |
|||
eventBus.once('事件名称', 优先级(可选), 回调函数, 上下文(可选)) |
|||
|
|||
## 取消监听事件 |
|||
// 取消监听 |
|||
eventBus.off('element.changed', callback) |
|||
|
|||
// 取消监听多个事件 |
|||
eventBus.off(['shape.added', 'connection.added', 'shape.removed', 'connection.removed'], callback) |
|||
|
|||
## 触发事件 |
|||
eventBus.fire('element.changed', data) |
|||
|
|||
```` |
|||
|
|||
## 画布 - canvas |
|||
|
|||
```` |
|||
## 获取画布模块 |
|||
let canvas = bpmnModeler.get("canvas") |
|||
|
|||
## 缩放 |
|||
|
|||
/** |
|||
* |
|||
* @param {'fit-viewport' | 'fit-content' | number} lvl |
|||
* @param {'auto'|{ x: number, y: number }} center |
|||
*/ |
|||
function zoom(lvl, center) { |
|||
let canvas = bpmnModeler.get('canvas') |
|||
canvas.zoom(lvl, center) |
|||
} |
|||
|
|||
// 适应容器缩放 |
|||
zoom('fit-canvas','auto') |
|||
|
|||
// 完全显示内容 |
|||
zoom('fit-content','auto') |
|||
|
|||
## 对齐(选择多个元素使用shift+鼠标左键) |
|||
/** |
|||
* 获取当前选集并对齐 |
|||
* @param {'left'|'right'|'top'|'bottom'|'middle'|'center'} mode |
|||
*/ |
|||
function align(mode) { |
|||
const align = bpmnModeler.get('alignElements') |
|||
const selection = bpmnModeler.get('selection') |
|||
const elements = selection.get() |
|||
if (!elements || elements.length === 0) { |
|||
return |
|||
} |
|||
|
|||
align.trigger(elements, mode) |
|||
} |
|||
|
|||
```` |
|||
|
|||
## 元素注册表 - elementRegistry |
|||
```` |
|||
## 获取元素注册表模块 |
|||
let elementRegistry = bpmnModeler.get('elementRegistry') |
|||
|
|||
## 遍历所有元素 |
|||
elementRegistry.forEach((shape, svgElement) => { }) |
|||
|
|||
## 获取指定元素 |
|||
let shape = elementRegistry.get(元素id或者SVGElement) |
|||
|
|||
## 获取过滤后的元素 |
|||
let shapes = elementRegistry.filter((shape) => shape.type === 'bpmn:Task') |
|||
|
|||
## 更新元素ID |
|||
elementRegistry.updateId(shape, "123xxxxsssd") |
|||
|
|||
## 删除一个元素 |
|||
elementRegistry .remove(传入SVGElement) |
|||
|
|||
## 模型 - moddle |
|||
基本上没有用到,具体类型定义见此 |
|||
|
|||
## 建模器 - modeling |
|||
获取建模器模块 |
|||
let modeling= bpmnModeler.get('modeling') |
|||
|
|||
## 修改元素显示文本(常用) |
|||
modeling.updateLabel(shape, '审核') |
|||
|
|||
## 修改元素属性(常用) |
|||
modeling.updateProperties(shape, { 属性名称: 属性值 }) |
|||
|
|||
## 对齐元素集合 |
|||
const selection = bpmnModeler.get('selection') |
|||
const elements = selection.get() |
|||
modeling.updateProperties(selection, 'left') |
|||
```` |
|||
@ -0,0 +1,120 @@ |
|||
import { NodeName } from '../lang/zh' |
|||
|
|||
// 创建监听器实例
|
|||
export function createListenerObject(moddle, options, isTask, prefix) { |
|||
const listenerObj = Object.create(null); |
|||
listenerObj.event = options.event; |
|||
isTask && (listenerObj.id = options.id); // 任务监听器特有的 id 字段
|
|||
switch (options.listenerType) { |
|||
case "scriptListener": |
|||
listenerObj.script = createScriptObject(moddle, options, prefix); |
|||
break; |
|||
case "expressionListener": |
|||
listenerObj.expression = options.expression; |
|||
break; |
|||
case "delegateExpressionListener": |
|||
listenerObj.delegateExpression = options.delegateExpression; |
|||
break; |
|||
default: |
|||
listenerObj.class = options.class; |
|||
} |
|||
// 注入字段
|
|||
if (options.fields) { |
|||
listenerObj.fields = options.fields.map(field => { |
|||
return createFieldObject(moddle, field, prefix); |
|||
}); |
|||
} |
|||
// 任务监听器的 定时器 设置
|
|||
if (isTask && options.event === "timeout" && !!options.eventDefinitionType) { |
|||
const timeDefinition = moddle.create("bpmn:FormalExpression", { |
|||
body: options.eventTimeDefinitions |
|||
}); |
|||
const TimerEventDefinition = moddle.create("bpmn:TimerEventDefinition", { |
|||
id: `TimerEventDefinition_${uuid(8)}`, |
|||
[`time${options.eventDefinitionType.replace(/^\S/, s => s.toUpperCase())}`]: timeDefinition |
|||
}); |
|||
listenerObj.eventDefinitions = [TimerEventDefinition]; |
|||
} |
|||
return moddle.create(`${prefix}:${isTask ? "TaskListener" : "ExecutionListener"}`, listenerObj); |
|||
} |
|||
|
|||
// 处理内置流程监听器
|
|||
export function createSystemListenerObject(moddle, options, isTask, prefix) { |
|||
const listenerObj = Object.create(null); |
|||
listenerObj.event = options.eventType; |
|||
listenerObj.listenerType = options.valueType; |
|||
switch (options.valueType) { |
|||
case "scriptListener": |
|||
listenerObj.script = createScriptObject(moddle, options, prefix); |
|||
break; |
|||
case "expressionListener": |
|||
listenerObj.expression = options.expression; |
|||
break; |
|||
case "delegateExpressionListener": |
|||
listenerObj.delegateExpression = options.delegateExpression; |
|||
break; |
|||
default: |
|||
listenerObj.class = options.value; |
|||
} |
|||
return moddle.create(`${prefix}:${isTask ? "TaskListener" : "ExecutionListener"}`, listenerObj); |
|||
} |
|||
|
|||
// 转换成字段
|
|||
export function changeListenerObject(options) { |
|||
const listenerObj = Object.create(null); |
|||
listenerObj.event = options.eventType; |
|||
listenerObj.listenerType = options.valueType; |
|||
switch (options.valueType) { |
|||
case "scriptListener": |
|||
// listenerObj.script = createScriptObject(moddle, options, prefix);
|
|||
break; |
|||
case "expressionListener": |
|||
listenerObj.expression = options.expression; |
|||
break; |
|||
case "delegateExpressionListener": |
|||
listenerObj.delegateExpression = options.delegateExpression; |
|||
break; |
|||
default: |
|||
listenerObj.class = options.value; |
|||
} |
|||
return listenerObj; |
|||
} |
|||
|
|||
// 创建 监听器的注入字段 实例
|
|||
export function createFieldObject(moddle, option, prefix) { |
|||
const { name, fieldType, string, expression } = option; |
|||
const fieldConfig = fieldType === "string" ? { name, string } : { name, expression }; |
|||
return moddle.create(`${prefix}:Field`, fieldConfig); |
|||
} |
|||
|
|||
// 创建脚本实例
|
|||
export function createScriptObject(moddle, options, prefix) { |
|||
const { scriptType, scriptFormat, value, resource } = options; |
|||
const scriptConfig = scriptType === "inlineScript" ? { scriptFormat, value } : { scriptFormat, resource }; |
|||
return moddle.create(`${prefix}:Script`, scriptConfig); |
|||
} |
|||
|
|||
// 更新元素扩展属性
|
|||
export function updateElementExtensions(moddle, modeling, element, extensionList) { |
|||
const extensions = moddle.create("bpmn:ExtensionElements", { |
|||
values: extensionList |
|||
}); |
|||
modeling.updateProperties(element, { |
|||
extensionElements: extensions |
|||
}); |
|||
} |
|||
|
|||
// 创建一个id
|
|||
export function uuid(length = 8, chars) { |
|||
let result = ""; |
|||
let charsString = chars || "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; |
|||
for (let i = length; i > 0; --i) { |
|||
result += charsString[Math.floor(Math.random() * charsString.length)]; |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
// 转换流程节点名称
|
|||
export function translateNodeName(node){ |
|||
return NodeName[node]; |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
// 全局流程相关变量
|
|||
const modelerStore = { |
|||
'userList': [], |
|||
'roleList': [], |
|||
'expList': [], |
|||
'modeler': null, |
|||
'modeling': null, |
|||
'moddle': null, |
|||
'canvas': null, |
|||
'bpmnFactory': null, |
|||
'elRegistry': null, |
|||
'element': null, |
|||
|
|||
} |
|||
export default |
|||
{ |
|||
modelerStore, |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
import inherits from "inherits"; |
|||
import Viewer from "bpmn-js/lib/Viewer"; |
|||
import ZoomScrollModule from "diagram-js/lib/navigation/zoomscroll"; |
|||
import MoveCanvasModule from "diagram-js/lib/navigation/movecanvas"; |
|||
function CustomViewer(options) { |
|||
Viewer.call(this, options); |
|||
} |
|||
inherits(CustomViewer, Viewer); |
|||
CustomViewer.prototype._modules = [].concat(Viewer.prototype._modules, [ZoomScrollModule, MoveCanvasModule]); |
|||
export { |
|||
CustomViewer |
|||
}; |
|||
@ -1,24 +0,0 @@ |
|||
|
|||
import executionListenerDialog from '../components/nodePanel/property/executionListener' |
|||
export default { |
|||
components: { |
|||
executionListenerDialog |
|||
}, |
|||
data() { |
|||
return { |
|||
executionListenerLength: 0, |
|||
dialogName: null |
|||
} |
|||
}, |
|||
methods: { |
|||
computedExecutionListenerLength() { |
|||
this.executionListenerLength = this.element.businessObject.extensionElements?.values?.length ?? 0 |
|||
}, |
|||
finishExecutionListener() { |
|||
if (this.dialogName === 'executionListenerDialog') { |
|||
this.computedExecutionListenerLength() |
|||
} |
|||
this.dialogName = '' |
|||
} |
|||
} |
|||
} |
|||
@ -1,70 +0,0 @@ |
|||
import xcrud from 'xcrud' |
|||
import golbalConfig from 'xcrud/package/common/config' |
|||
import showConfig from '../flowable/showConfig' |
|||
golbalConfig.set({ |
|||
input: { |
|||
// size: 'mini'
|
|||
}, |
|||
select: { |
|||
// size: 'mini'
|
|||
}, |
|||
colorPicker: { |
|||
showAlpha: true |
|||
}, |
|||
xform: { |
|||
form: { |
|||
labelWidth: 'auto' |
|||
// size: 'mini'
|
|||
} |
|||
} |
|||
}) |
|||
export default { |
|||
components: { xForm: xcrud.xForm }, |
|||
props: { |
|||
modeler: { |
|||
type: Object, |
|||
required: true |
|||
}, |
|||
element: { |
|||
type: Object, |
|||
required: true |
|||
}, |
|||
categorys: { |
|||
type: Array, |
|||
default: () => [] |
|||
} |
|||
}, |
|||
watch: { |
|||
'formData.id': function(val) { |
|||
this.updateProperties({ id: val }) |
|||
}, |
|||
'formData.name': function(val) { |
|||
this.updateProperties({ name: val }) |
|||
}, |
|||
'formData.documentation': function(val) { |
|||
if (!val) { |
|||
this.updateProperties({ documentation: [] }) |
|||
return |
|||
} |
|||
const documentationElement = this.modeler.get('moddle').create('bpmn:Documentation', { text: val }) |
|||
this.updateProperties({ documentation: [documentationElement] }) |
|||
} |
|||
}, |
|||
methods: { |
|||
updateProperties(properties) { |
|||
const modeling = this.modeler.get('modeling') |
|||
modeling.updateProperties(this.element, properties) |
|||
} |
|||
}, |
|||
computed: { |
|||
elementType() { |
|||
const bizObj = this.element.businessObject |
|||
return bizObj.eventDefinitions |
|||
? bizObj.eventDefinitions[0].$type |
|||
: bizObj.$type |
|||
}, |
|||
showConfig() { |
|||
return showConfig[this.elementType] || {} |
|||
} |
|||
} |
|||
} |
|||
@ -1,22 +0,0 @@ |
|||
import xcrud from 'xcrud' |
|||
import golbalConfig from 'xcrud/package/common/config' |
|||
golbalConfig.set({ |
|||
input: { |
|||
// size: 'mini'
|
|||
}, |
|||
select: { |
|||
// size: 'mini'
|
|||
}, |
|||
colorPicker: { |
|||
showAlpha: true |
|||
}, |
|||
xform: { |
|||
form: { |
|||
labelWidth: 'auto' |
|||
// size: 'mini'
|
|||
} |
|||
} |
|||
}) |
|||
export default { |
|||
components: { xForm: xcrud.xForm } |
|||
} |
|||
File diff suppressed because it is too large
@ -1,55 +0,0 @@ |
|||
export function commonParse(element) { |
|||
const result = { |
|||
...element.businessObject, |
|||
...element.businessObject.$attrs |
|||
} |
|||
return formatJsonKeyValue(result) |
|||
} |
|||
|
|||
export function formatJsonKeyValue(result) { |
|||
// 移除flowable前缀,格式化数组
|
|||
for (const key in result) { |
|||
if (key.indexOf('flowable:') === 0) { |
|||
const newKey = key.replace('flowable:', '') |
|||
result[newKey] = result[key] |
|||
delete result[key] |
|||
} |
|||
} |
|||
result = documentationParse(result) |
|||
return result |
|||
} |
|||
|
|||
export function documentationParse(obj) { |
|||
if ('documentation' in obj) { |
|||
let str = '' |
|||
obj.documentation.forEach(item => { |
|||
str += item.text |
|||
}) |
|||
obj.documentation = str |
|||
} |
|||
return obj |
|||
} |
|||
|
|||
export function conditionExpressionParse(obj) { |
|||
if ('conditionExpression' in obj) { |
|||
if (obj.conditionExpression) { |
|||
obj.conditionExpression = obj.conditionExpression.body |
|||
} |
|||
} |
|||
return obj |
|||
} |
|||
|
|||
export function userTaskParse(obj) { |
|||
for (const key in obj) { |
|||
if (key === 'candidateUsers') { |
|||
obj.userType = 'candidateUsers' |
|||
obj[key] = obj[key]?.split(',') || [] |
|||
} else if (key === 'candidateGroups') { |
|||
obj.userType = 'candidateGroups' |
|||
obj[key] = obj[key]?.split(',') || [] |
|||
} else if (key === 'assignee') { |
|||
obj.userType = 'assignee' |
|||
} |
|||
} |
|||
return obj |
|||
} |
|||
@ -1,24 +0,0 @@ |
|||
export default class CustomContextPad { |
|||
constructor(config, contextPad, create, elementFactory, injector, translate) { |
|||
this.create = create; |
|||
this.elementFactory = elementFactory; |
|||
this.translate = translate; |
|||
|
|||
if (config.autoPlace !== false) { |
|||
this.autoPlace = injector.get('autoPlace', false); |
|||
} |
|||
|
|||
contextPad.registerProvider(this); // 定义这是一个contextPad |
|||
} |
|||
|
|||
getContextPadEntries(element) {} |
|||
} |
|||
|
|||
CustomContextPad.$inject = [ |
|||
'config', |
|||
'contextPad', |
|||
'create', |
|||
'elementFactory', |
|||
'injector', |
|||
'translate' |
|||
]; |
|||
@ -1,81 +0,0 @@ |
|||
<template> |
|||
<div> |
|||
<x-form ref="xForm" v-model="formData" :config="formConfig"> |
|||
<template #executionListener> |
|||
<el-badge :value="executionListenerLength"> |
|||
<el-button size="small" @click="dialogName = 'executionListenerDialog'">编辑</el-button> |
|||
</el-badge> |
|||
</template> |
|||
</x-form> |
|||
<executionListenerDialog |
|||
v-if="dialogName === 'executionListenerDialog'" |
|||
:element="element" |
|||
:modeler="modeler" |
|||
@close="finishExecutionListener" |
|||
/> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import mixinPanel from '../../common/mixinPanel' |
|||
import mixinExecutionListener from '../../common/mixinExecutionListener' |
|||
import { commonParse } from '../../common/parseElement' |
|||
export default { |
|||
mixins: [mixinPanel, mixinExecutionListener], |
|||
data() { |
|||
return { |
|||
formData: {} |
|||
} |
|||
}, |
|||
computed: { |
|||
formConfig() { |
|||
return { |
|||
inline: false, |
|||
item: [ |
|||
{ |
|||
xType: 'input', |
|||
name: 'id', |
|||
label: '节点 id', |
|||
rules: [{ required: true, message: 'Id 不能为空' }] |
|||
}, |
|||
{ |
|||
xType: 'input', |
|||
name: 'name', |
|||
label: '节点名称' |
|||
}, |
|||
{ |
|||
xType: 'input', |
|||
name: 'documentation', |
|||
label: '节点描述' |
|||
}, |
|||
{ |
|||
xType: 'slot', |
|||
name: 'executionListener', |
|||
label: '执行监听器' |
|||
}, |
|||
{ |
|||
xType: 'switch', |
|||
name: 'async', |
|||
label: '异步', |
|||
activeText: '是', |
|||
inactiveText: '否' |
|||
} |
|||
] |
|||
} |
|||
} |
|||
}, |
|||
watch: { |
|||
'formData.async': function(val) { |
|||
if (val === '') val = null |
|||
this.updateProperties({ 'flowable:async': val }) |
|||
} |
|||
}, |
|||
created() { |
|||
this.formData = commonParse(this.element) |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
|
|||
</style> |
|||
@ -1,113 +0,0 @@ |
|||
<template> |
|||
<div> |
|||
<x-form ref="xForm" v-model="formData" :config="formConfig"> |
|||
<template #executionListener> |
|||
<el-badge :value="executionListenerLength"> |
|||
<el-button size="small" @click="dialogName = 'executionListenerDialog'">编辑</el-button> |
|||
</el-badge> |
|||
</template> |
|||
<template #signal> |
|||
<el-badge :value="signalLength"> |
|||
<el-button size="small" @click="dialogName = 'signalDialog'">编辑</el-button> |
|||
</el-badge> |
|||
</template> |
|||
</x-form> |
|||
<executionListenerDialog |
|||
v-if="dialogName === 'executionListenerDialog'" |
|||
:element="element" |
|||
:modeler="modeler" |
|||
@close="finishExecutionListener" |
|||
/> |
|||
<signalDialog |
|||
v-if="dialogName === 'signalDialog'" |
|||
:element="element" |
|||
:modeler="modeler" |
|||
@close="finishExecutionListener" |
|||
/> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import mixinPanel from '../../common/mixinPanel' |
|||
import mixinExecutionListener from '../../common/mixinExecutionListener' |
|||
import signalDialog from './property/signal' |
|||
import { commonParse } from '../../common/parseElement' |
|||
export default { |
|||
components: { |
|||
signalDialog |
|||
}, |
|||
mixins: [mixinPanel, mixinExecutionListener], |
|||
data() { |
|||
return { |
|||
signalLength: 0, |
|||
formData: {} |
|||
} |
|||
}, |
|||
computed: { |
|||
formConfig() { |
|||
const _this = this |
|||
return { |
|||
inline: false, |
|||
item: [ |
|||
{ |
|||
xType: 'select', |
|||
name: 'processCategory', |
|||
label: '流程分类', |
|||
dic: { data: _this.categorys, label: 'dictLabel', value: 'dictValue' } |
|||
}, |
|||
{ |
|||
xType: 'input', |
|||
name: 'id', |
|||
label: '流程标识key', |
|||
rules: [{ required: true, message: 'Id 不能为空' }] |
|||
}, |
|||
{ |
|||
xType: 'input', |
|||
name: 'name', |
|||
label: '流程名称' |
|||
}, |
|||
{ |
|||
xType: 'input', |
|||
name: 'documentation', |
|||
label: '节点描述' |
|||
}, |
|||
{ |
|||
xType: 'slot', |
|||
name: 'executionListener', |
|||
label: '执行监听器' |
|||
}, |
|||
{ |
|||
xType: 'slot', |
|||
name: 'signal', |
|||
label: '信号定义' |
|||
} |
|||
] |
|||
} |
|||
} |
|||
}, |
|||
watch: { |
|||
'formData.processCategory': function(val) { |
|||
if (val === '') val = null |
|||
this.updateProperties({ 'flowable:processCategory': val }) |
|||
} |
|||
}, |
|||
created() { |
|||
this.formData = commonParse(this.element) |
|||
}, |
|||
methods: { |
|||
computedSignalLength() { |
|||
this.signalLength = this.element.businessObject.extensionElements?.values?.length ?? 0 |
|||
}, |
|||
finishSignal() { |
|||
if (this.dialogName === 'signalDialog') { |
|||
this.computedSignalLength() |
|||
} |
|||
this.dialogName = '' |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
|
|||
</style> |
|||
@ -1,217 +0,0 @@ |
|||
<template> |
|||
<div> |
|||
<el-dialog |
|||
title="执行监听器" |
|||
:visible.sync="dialogVisible" |
|||
width="900px" |
|||
:close-on-click-modal="false" |
|||
:close-on-press-escape="false" |
|||
:show-close="false" |
|||
@closed="$emit('close')" |
|||
> |
|||
<x-form ref="xForm" v-model="formData" :config="formConfig"> |
|||
<template #params="scope"> |
|||
<el-badge :value="scope.row.params ? scope.row.params.length : 0" type="primary"> |
|||
<el-button size="small" @click="configParam(scope.$index)">配置</el-button> |
|||
</el-badge> |
|||
</template> |
|||
</x-form> |
|||
<span slot="footer" class="dialog-footer"> |
|||
<el-button type="primary" size="medium" @click="closeDialog">确 定</el-button> |
|||
</span> |
|||
<listener-list |
|||
:visible="listenerDialogVisible" |
|||
@close="() => this.listenerDialogVisible = false" |
|||
@submit="addListener" |
|||
/> |
|||
</el-dialog> |
|||
<listenerParam v-if="showParamDialog" :value="formData.executionListener[nowIndex].params" @close="finishConfigParam" /> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import mixinPanel from '../../../common/mixinPanel' |
|||
import listenerParam from './listenerParam' |
|||
import FlowListener from '@/components/flow/Listener' |
|||
import ListenerList from '@/components/Process/components/nodePanel/property/listenerList' |
|||
export default { |
|||
components: { ListenerList, listenerParam, FlowListener }, |
|||
mixins: [mixinPanel], |
|||
data() { |
|||
return { |
|||
dialogVisible: true, |
|||
listenerDialogVisible: false, |
|||
showParamDialog: false, |
|||
nowIndex: null, |
|||
formData: { |
|||
executionListener: [] |
|||
} |
|||
} |
|||
}, |
|||
computed: { |
|||
formConfig() { |
|||
// const _this = this |
|||
return { |
|||
inline: false, |
|||
item: [ |
|||
{ |
|||
xType: 'tabs', |
|||
tabs: [ |
|||
{ |
|||
label: '执行监听器', |
|||
name: 'executionListener', |
|||
column: [ |
|||
{ |
|||
label: '事件', |
|||
name: 'event', |
|||
width: 180, |
|||
rules: [{ required: true, message: '请选择', trigger: ['blur', 'change'] }], |
|||
xType: 'select', |
|||
dic: [ |
|||
{ label: 'start', value: 'start' }, |
|||
{ label: 'end', value: 'end' }, |
|||
{ label: 'take', value: 'take' } |
|||
] |
|||
}, |
|||
{ |
|||
label: '类型', |
|||
name: 'type', |
|||
width: 180, |
|||
rules: [{ required: true, message: '请选择', trigger: ['blur', 'change'] }], |
|||
xType: 'select', |
|||
dic: [ |
|||
{ label: '类', value: 'class' }, |
|||
{ label: '表达式', value: 'expression' }, |
|||
{ label: '委托表达式', value: 'delegateExpression' } |
|||
], |
|||
tooltip: `类:示例 com.company.MyCustomListener,自定义类必须实现 org.flowable.engine.delegate.ExecutionListener 接口 <br /> |
|||
表达式:示例 \${myObject.callMethod(task, task.eventName)} <br /> |
|||
委托表达式:示例 \${myListenerSpringBean} ,该 springBean 需要实现 org.flowable.engine.delegate.ExecutionListener 接口 |
|||
` |
|||
}, |
|||
{ |
|||
label: '值', |
|||
name: 'className', |
|||
xType: 'input', |
|||
rules: [{ required: true, message: '请输入', trigger: ['blur', 'change'] }] |
|||
}, |
|||
{ |
|||
xType: 'slot', |
|||
label: '参数', |
|||
width: 120, |
|||
slot: true, |
|||
name: 'params' |
|||
} |
|||
] |
|||
} |
|||
] |
|||
} |
|||
] |
|||
} |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.$nextTick(() => this.addButton()) |
|||
this.formData.executionListener = this.element.businessObject.extensionElements?.values |
|||
.filter(item => item.$type === 'flowable:ExecutionListener') |
|||
.map(item => { |
|||
let type |
|||
if ('class' in item) type = 'class' |
|||
if ('expression' in item) type = 'expression' |
|||
if ('delegateExpression' in item) type = 'delegateExpression' |
|||
return { |
|||
event: item.event, |
|||
type: type, |
|||
className: item[type], |
|||
params: item.fields?.map(field => { |
|||
let fieldType |
|||
if ('stringValue' in field) fieldType = 'stringValue' |
|||
if ('expression' in field) fieldType = 'expression' |
|||
return { |
|||
name: field.name, |
|||
type: fieldType, |
|||
value: field[fieldType] |
|||
} |
|||
}) ?? [] |
|||
} |
|||
}) ?? [] |
|||
}, |
|||
methods: { |
|||
addButton() { |
|||
const button = document.createElement('button') |
|||
button.innerText = '内置监听器' |
|||
button.setAttribute('type', 'button') |
|||
button.setAttribute('class', 'el-button el-button--primary el-button--mini') |
|||
button.addEventListener('click', () => this.listenerDialogVisible = true) |
|||
const div = document.getElementById('pane-executionListener') |
|||
const table = div.getElementsByClassName('el-table')[0] |
|||
div.insertBefore(button, table) |
|||
}, |
|||
configParam(index) { |
|||
this.nowIndex = index |
|||
const nowObj = this.formData.executionListener[index] |
|||
if (!nowObj.params) { |
|||
nowObj.params = [] |
|||
} |
|||
this.showParamDialog = true |
|||
}, |
|||
finishConfigParam(param) { |
|||
this.showParamDialog = false |
|||
// hack 数量不更新问题 |
|||
const cache = this.formData.executionListener[this.nowIndex] |
|||
cache.params = param |
|||
this.$set(this.formData.executionListener[this.nowIndex], this.nowIndex, cache) |
|||
this.nowIndex = null |
|||
}, |
|||
updateElement() { |
|||
if (this.formData.executionListener?.length) { |
|||
let extensionElements = this.element.businessObject.get('extensionElements') |
|||
if (!extensionElements) { |
|||
extensionElements = this.modeler.get('moddle').create('bpmn:ExtensionElements') |
|||
} |
|||
// 清除旧值 |
|||
extensionElements.values = extensionElements.values?.filter(item => item.$type !== 'flowable:ExecutionListener') ?? [] |
|||
this.formData.executionListener.forEach(item => { |
|||
const executionListener = this.modeler.get('moddle').create('flowable:ExecutionListener') |
|||
executionListener['event'] = item.event |
|||
executionListener[item.type] = item.className |
|||
if (item.params && item.params.length) { |
|||
item.params.forEach(field => { |
|||
const fieldElement = this.modeler.get('moddle').create('flowable:Field') |
|||
fieldElement['name'] = field.name |
|||
fieldElement[field.type] = field.value |
|||
// 注意:flowable.json 中定义的string和expression类为小写,不然会和原生的String类冲突,此处为hack |
|||
// const valueElement = this.modeler.get('moddle').create(`flowable:${field.type}`, { body: field.value }) |
|||
// fieldElement[field.type] = valueElement |
|||
executionListener.get('fields').push(fieldElement) |
|||
}) |
|||
} |
|||
extensionElements.get('values').push(executionListener) |
|||
}) |
|||
this.updateProperties({ extensionElements: extensionElements }) |
|||
} else { |
|||
const extensionElements = this.element.businessObject[`extensionElements`] |
|||
if (extensionElements) { |
|||
extensionElements.values = extensionElements.values?.filter(item => item.$type !== 'flowable:ExecutionListener') ?? [] |
|||
} |
|||
} |
|||
}, |
|||
closeDialog() { |
|||
console.log(this.formData) |
|||
this.$refs.xForm.validate().then(() => { |
|||
this.updateElement() |
|||
this.dialogVisible = false |
|||
}).catch(e => console.error(e)) |
|||
}, |
|||
addListener(data) { |
|||
this.formData.executionListener = this.formData.executionListener.concat(data) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
.flow-containers .el-badge__content.is-fixed { |
|||
top: 18px; |
|||
} |
|||
</style> |
|||
@ -1,72 +0,0 @@ |
|||
<template> |
|||
<el-dialog title="内置监听器" |
|||
width="900px" |
|||
:visible.sync="dialogVisible" |
|||
append-to-body |
|||
:close-on-click-modal="false" |
|||
:close-on-press-escape="false" |
|||
:show-close="false" |
|||
:before-close="close" |
|||
> |
|||
<flow-listener @handleSelect="handleSelect"/> |
|||
<span slot="footer" class="dialog-footer"> |
|||
<el-button @click="close">取 消</el-button> |
|||
<el-button type="primary" @click="checkComplete">确 定</el-button> |
|||
</span> |
|||
</el-dialog> |
|||
</template> |
|||
|
|||
<script> |
|||
import FlowListener from '@/components/flow/Listener' |
|||
|
|||
export default { |
|||
name: 'ListentList', |
|||
components: { FlowListener }, |
|||
props: { |
|||
visible: { |
|||
type: Boolean, |
|||
default: false |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
dialogVisible: this.visible, |
|||
listenerList: [] |
|||
} |
|||
}, |
|||
watch: { |
|||
visible: { |
|||
handler(newVal) { |
|||
this.dialogVisible = newVal |
|||
}, |
|||
immediate: true, |
|||
deep: true |
|||
} |
|||
}, |
|||
methods: { |
|||
close() { |
|||
this.dialogVisible = false |
|||
this.$emit('close') |
|||
}, |
|||
checkComplete() { |
|||
this.close() |
|||
this.$emit('submit', this.listenerList) |
|||
}, |
|||
handleSelect(selection) { |
|||
const type = ['class', 'expression', 'delegateExpression'] |
|||
let list = [] |
|||
selection.forEach(data => { |
|||
const formData = { |
|||
event: data.eventType, |
|||
type: type[parseInt(data.valueType) - 1], |
|||
className: data.value |
|||
} |
|||
list.push(formData) |
|||
}) |
|||
this.listenerList = list |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style></style> |
|||
@ -1,96 +0,0 @@ |
|||
<template> |
|||
<div> |
|||
<el-dialog |
|||
title="监听器参数" |
|||
:visible.sync="dialogVisible" |
|||
width="700px" |
|||
:close-on-click-modal="false" |
|||
:close-on-press-escape="false" |
|||
:show-close="false" |
|||
@closed="$emit('close', formData.paramList)" |
|||
> |
|||
<x-form ref="xForm" v-model="formData" :config="formConfig" /> |
|||
<span slot="footer" class="dialog-footer"> |
|||
<el-button type="primary" size="medium" @click="closeDialog">确 定</el-button> |
|||
</span> |
|||
</el-dialog> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import mixinXcrud from '../../../common/mixinXcrud' |
|||
export default { |
|||
mixins: [mixinXcrud], |
|||
props: { |
|||
value: { |
|||
type: Array, |
|||
default: () => [] |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
dialogVisible: true, |
|||
formData: { |
|||
paramList: this.value |
|||
} |
|||
} |
|||
}, |
|||
computed: { |
|||
formConfig() { |
|||
return { |
|||
inline: false, |
|||
item: [ |
|||
{ |
|||
xType: 'tabs', |
|||
tabs: [ |
|||
{ |
|||
label: '监听器参数', |
|||
name: 'paramList', |
|||
column: [ |
|||
{ |
|||
label: '类型', |
|||
name: 'type', |
|||
width: 180, |
|||
rules: [{ required: true, message: '请选择', trigger: ['blur', 'change'] }], |
|||
xType: 'select', |
|||
dic: [ |
|||
{ label: '字符串', value: 'stringValue' }, |
|||
{ label: '表达式', value: 'expression' } |
|||
] |
|||
}, |
|||
{ |
|||
label: '名称', |
|||
name: 'name', |
|||
width: 180, |
|||
rules: [{ required: true, message: '请选择', trigger: ['blur', 'change'] }], |
|||
xType: 'input' |
|||
}, |
|||
{ |
|||
label: '值', |
|||
name: 'value', |
|||
xType: 'input', |
|||
rules: [{ required: true, message: '请输入', trigger: ['blur', 'change'] }] |
|||
} |
|||
] |
|||
} |
|||
] |
|||
} |
|||
] |
|||
} |
|||
} |
|||
}, |
|||
methods: { |
|||
closeDialog() { |
|||
this.$refs.xForm.validate().then(() => { |
|||
this.dialogVisible = false |
|||
}).catch(e => console.error(e)) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
.flow-containers .el-badge__content.is-fixed { |
|||
top: 18px; |
|||
} |
|||
</style> |
|||
@ -1,133 +0,0 @@ |
|||
<template> |
|||
<div> |
|||
<el-dialog |
|||
title="多实例配置" |
|||
:visible.sync="dialogVisible" |
|||
width="600px" |
|||
:close-on-click-modal="false" |
|||
:close-on-press-escape="false" |
|||
class="muti-instance" |
|||
@closed="$emit('close')" |
|||
> |
|||
<el-descriptions :column="1" size="mini" border> |
|||
<el-descriptions-item label="使用说明">按照BPMN2.0规范的要求,用于为每个实例创建执行的父执行,会提供下列变量:</el-descriptions-item> |
|||
<el-descriptions-item label="nrOfInstances">实例总数。</el-descriptions-item> |
|||
<el-descriptions-item label="nrOfActiveInstances">当前活动的(即未完成的),实例数量。对于顺序多实例,这个值总为1。</el-descriptions-item> |
|||
<el-descriptions-item label="nrOfCompletedInstances">已完成的实例数量。</el-descriptions-item> |
|||
<el-descriptions-item label="loopCounter">给定实例在for-each循环中的index。</el-descriptions-item> |
|||
</el-descriptions> |
|||
<div class="app-container"> |
|||
<x-form ref="xForm" v-model="formData" :config="formConfig" /> |
|||
</div> |
|||
</el-dialog> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import mixinPanel from '@/components/Process/common/mixinPanel' |
|||
import {formatJsonKeyValue} from '@/components/Process/common/parseElement' |
|||
|
|||
export default { |
|||
mixins: [mixinPanel], |
|||
data() { |
|||
return { |
|||
dialogVisible: true, |
|||
formData: {}, |
|||
prefix: 'flowable:', |
|||
} |
|||
}, |
|||
computed: { |
|||
formConfig() { |
|||
const _this = this |
|||
return { |
|||
inline: false, |
|||
item: [ |
|||
{ |
|||
xType: 'input', |
|||
name: 'collection', |
|||
label: '集合', |
|||
tooltip: 'collection: 属性会作为表达式进行解析。如果表达式解析为字符串而不是一个集合,<br />不论是因为本身配置的就是静态字符串值,还是表达式计算结果为字符串,<br />这个字符串都会被当做变量名,并从流程变量中用于获取实际的集合。', |
|||
// rules: [{ required: true, message: '请输入集合名称', trigger: ['blur', 'change'] }] |
|||
}, |
|||
{ |
|||
xType: 'input', |
|||
name: 'elementVariable', |
|||
label: '元素变量', |
|||
tooltip: 'elementVariable: 每创建一个用户任务前,先以该元素变量为label,集合中的一项为value,<br />创建(局部)流程变量,该局部流程变量被用于指派用户任务。<br />一般来说,该字符串应与指定人员变量相同。', |
|||
// rules: [{ required: true, message: '请输入元素变量', trigger: ['blur', 'change'] }] |
|||
}, |
|||
{ |
|||
xType: 'select', |
|||
name: 'isSequential', |
|||
label: '执行方式', |
|||
tooltip: '并行会签(parallel)、串行会签(sequential),其中并行会签的意思是 多个人同时执行任务。串行会签是按顺序执行任务。', |
|||
dic: [{label: '串行', value: true}, {label: '并行', value: false}], |
|||
// rules: [{ required: true, message: '请选择执行方式', trigger: ['blur', 'change'] }] |
|||
}, |
|||
{ |
|||
xType: 'input', |
|||
name: 'completionCondition', |
|||
label: '完成条件', |
|||
tooltip: 'completionCondition: 多实例活动在所有实例都完成时结束,然而也可以指定一个表达式,在每个实例<br />结束时进行计算。当表达式计算为true时,将销毁所有剩余的实例,并结束多实例<br />活动,继续执行流程。例如 ${nrOfCompletedInstances/nrOfInstances >= 0.6 },<br />表示当任务完成60%时,该节点就算完成', |
|||
// rules: [{ required: true, message: '请输入完成条件', trigger: ['blur', 'change'] }] |
|||
} |
|||
], |
|||
operate: [ |
|||
{ text: '确定', show: true, click: _this.save }, |
|||
{ text: '清空', show: true, click: () => { _this.formData = {} } } |
|||
] |
|||
} |
|||
} |
|||
}, |
|||
mounted() { |
|||
const cache = JSON.parse(JSON.stringify(this.element.businessObject.loopCharacteristics ?? {})) |
|||
cache.completionCondition = cache.completionCondition?.body |
|||
// 拼接多实例对象 |
|||
if (this.element.businessObject.loopCharacteristics) { |
|||
Object.assign(cache, this.element.businessObject.loopCharacteristics.$attrs) |
|||
} |
|||
this.formData = formatJsonKeyValue(cache) |
|||
}, |
|||
methods: { |
|||
updateElement() { |
|||
if (this.formData.isSequential !== null && this.formData.isSequential !== undefined) { |
|||
// const model = this.modeler.get('moddle'); |
|||
let loopCharacteristics = this.element.businessObject.get('loopCharacteristics') |
|||
if (!loopCharacteristics) { |
|||
loopCharacteristics = this.modeler.get('moddle').create('bpmn:MultiInstanceLoopCharacteristics') |
|||
} |
|||
loopCharacteristics['isSequential'] = this.formData.isSequential |
|||
loopCharacteristics['collection'] = this.formData.collection |
|||
loopCharacteristics['elementVariable'] = this.formData.elementVariable |
|||
// let loopCardinality = model.create("bpmn:Expression",{ |
|||
// body: "4" |
|||
// }); |
|||
// loopCharacteristics['loopCardinality'] = loopCardinality |
|||
|
|||
loopCharacteristics.$attrs['isSequential'] = this.formData.isSequential |
|||
loopCharacteristics.$attrs[this.prefix + 'collection'] = this.formData.collection |
|||
loopCharacteristics.$attrs[this.prefix + 'elementVariable'] = this.formData.elementVariable |
|||
|
|||
if (this.formData.completionCondition) { |
|||
loopCharacteristics['completionCondition'] = this.modeler.get('moddle').create('bpmn:Expression', {body: this.formData.completionCondition}) |
|||
} |
|||
this.updateProperties({loopCharacteristics: loopCharacteristics}) |
|||
} else { |
|||
delete this.element.businessObject.loopCharacteristics |
|||
} |
|||
}, |
|||
save() { |
|||
this.$refs['xForm'].validate().then(() => { |
|||
this.updateElement() |
|||
this.dialogVisible = false |
|||
}).catch(e => console.error(e)); |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
.muti-instance .el-form-item { |
|||
margin-bottom: 22px; |
|||
} |
|||
</style> |
|||
@ -1,147 +0,0 @@ |
|||
<template> |
|||
<div> |
|||
<el-dialog |
|||
title="信号定义" |
|||
:visible.sync="dialogVisible" |
|||
width="700px" |
|||
:close-on-click-modal="false" |
|||
:close-on-press-escape="false" |
|||
:show-close="false" |
|||
@closed="$emit('close')" |
|||
> |
|||
<x-form ref="xForm" v-model="formData" :config="formConfig" /> |
|||
<span slot="footer" class="dialog-footer"> |
|||
<el-button type="primary" size="medium" @click="closeDialog">确 定</el-button> |
|||
</span> |
|||
</el-dialog> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import mixinPanel from '../../../common/mixinPanel' |
|||
export default { |
|||
mixins: [mixinPanel], |
|||
data() { |
|||
return { |
|||
dialogVisible: true, |
|||
formData: { |
|||
signal: [] |
|||
} |
|||
} |
|||
}, |
|||
computed: { |
|||
formConfig() { |
|||
// const _this = this |
|||
return { |
|||
inline: false, |
|||
item: [ |
|||
{ |
|||
xType: 'tabs', |
|||
tabs: [ |
|||
{ |
|||
label: '信号定义', |
|||
name: 'signal', |
|||
column: [ |
|||
{ |
|||
label: 'scope', |
|||
name: 'scope', |
|||
width: 180, |
|||
rules: [{ required: true, message: '请选择', trigger: ['blur', 'change'] }], |
|||
xType: 'select', |
|||
dic: [ |
|||
{ label: '全局', value: 'start' }, |
|||
{ label: '流程实例', value: 'end' } |
|||
] |
|||
}, |
|||
{ |
|||
label: 'id', |
|||
name: 'id', |
|||
width: 200, |
|||
rules: [{ required: true, message: '请输入', trigger: ['blur', 'change'] }], |
|||
xType: 'input' |
|||
}, |
|||
{ |
|||
label: '名称', |
|||
name: 'name', |
|||
xType: 'input', |
|||
rules: [{ required: true, message: '请输入', trigger: ['blur', 'change'] }] |
|||
} |
|||
] |
|||
} |
|||
] |
|||
} |
|||
] |
|||
} |
|||
} |
|||
}, |
|||
mounted() { |
|||
// this.formData.signal = this.element.businessObject.extensionElements?.values.map(item => { |
|||
this.formData.signal = this.element.businessObject.extensionElements?.values |
|||
.filter(item => item.$type === 'bpmn:Signal') |
|||
.map(item => { |
|||
return { |
|||
scope: item.scope, |
|||
id: item.id, |
|||
name: item.name |
|||
} |
|||
}) ?? [] |
|||
}, |
|||
methods: { |
|||
updateElement() { |
|||
// if (this.formData.signal?.length) { |
|||
// let extensionElements = this.element.businessObject.get('extensionElements') |
|||
// if (!extensionElements) { |
|||
// console.log(this.modeler.get('moddle'),"this.modeler.get('moddle')") |
|||
// extensionElements = this.modeler.get('moddle').create('bpmn:Signal') |
|||
// } |
|||
// extensionElements.values = extensionElements.values?.filter(item => item.$type !== 'bpmn:Signal') ?? [] |
|||
// console.log(extensionElements,"extensionElements") |
|||
// const length = extensionElements.get('values').length |
|||
// for (let i = 0; i < length; i++) { |
|||
// // 清除旧值 |
|||
// extensionElements.get('values').pop() |
|||
// } |
|||
// this.updateProperties({ extensionElements: extensionElements }) |
|||
// } else { |
|||
// const extensionElements = this.element.businessObject[`extensionElements`] |
|||
// if (extensionElements) { |
|||
// extensionElements.values = extensionElements.values?.filter(item => item.$type !== 'flowable:ExecutionListener') |
|||
// } |
|||
// } |
|||
if (this.formData.signal?.length) { |
|||
let extensionElements = this.element.businessObject.get('extensionElements') |
|||
if (!extensionElements) { |
|||
extensionElements = this.modeler.get('moddle').create('bpmn:ExtensionElements') |
|||
} |
|||
// 清除旧值 |
|||
extensionElements.values = extensionElements.values?.filter(item => item.$type !== 'bpmn:Signal') ?? [] |
|||
this.formData.signal.forEach(item => { |
|||
const signal = this.modeler.get('moddle').create('bpmn:Signal') |
|||
signal['scope'] = item.scope |
|||
signal['id'] = item.id |
|||
signal['name'] = item.name |
|||
extensionElements.get('values').push(signal) |
|||
}) |
|||
this.updateProperties({ extensionElements: extensionElements }) |
|||
} else { |
|||
const extensionElements = this.element.businessObject[`extensionElements`] |
|||
if (extensionElements) { |
|||
extensionElements.values = extensionElements.values?.filter(item => item.$type !== 'bpmn:Signal') ?? [] |
|||
} |
|||
} |
|||
}, |
|||
closeDialog() { |
|||
this.$refs.xForm.validate().then(() => { |
|||
this.updateElement() |
|||
this.dialogVisible = false |
|||
}).catch(e => console.error(e)) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
.flow-containers .el-badge__content.is-fixed { |
|||
top: 18px; |
|||
} |
|||
</style> |
|||
@ -1,221 +0,0 @@ |
|||
<template> |
|||
<div> |
|||
<el-dialog |
|||
title="任务监听器" |
|||
:visible.sync="dialogVisible" |
|||
width="900px" |
|||
:close-on-click-modal="false" |
|||
:close-on-press-escape="false" |
|||
:show-close="false" |
|||
@closed="$emit('close')" |
|||
> |
|||
<x-form ref="xForm" v-model="formData" :config="formConfig"> |
|||
<template #params="scope"> |
|||
<el-badge :value="scope.row.params ? scope.row.params.length : 0" type="primary"> |
|||
<el-button size="small" @click="configParam(scope.$index)">配置</el-button> |
|||
</el-badge> |
|||
</template> |
|||
</x-form> |
|||
<span slot="footer" class="dialog-footer"> |
|||
<el-button type="primary" size="medium" @click="closeDialog">确 定</el-button> |
|||
</span> |
|||
<listener-list |
|||
:visible="listenerDialogVisible" |
|||
@close="() => this.listenerDialogVisible = false" |
|||
@submit="addListener" |
|||
/> |
|||
</el-dialog> |
|||
<listenerParam v-if="showParamDialog" :value="formData.taskListener[nowIndex].params" @close="finishConfigParam" /> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import mixinPanel from '../../../common/mixinPanel' |
|||
import listenerParam from './listenerParam' |
|||
import ListenerList from '@/components/Process/components/nodePanel/property/listenerList' |
|||
export default { |
|||
components: { listenerParam, ListenerList }, |
|||
mixins: [mixinPanel], |
|||
data() { |
|||
return { |
|||
dialogVisible: true, |
|||
listenerDialogVisible: false, |
|||
showParamDialog: false, |
|||
nowIndex: null, |
|||
formData: { |
|||
taskListener: [] |
|||
} |
|||
} |
|||
}, |
|||
computed: { |
|||
formConfig() { |
|||
// const _this = this |
|||
return { |
|||
inline: false, |
|||
item: [ |
|||
{ |
|||
xType: 'tabs', |
|||
tabs: [ |
|||
{ |
|||
label: '任务监听器', |
|||
name: 'taskListener', |
|||
column: [ |
|||
{ |
|||
label: '事件', |
|||
name: 'event', |
|||
width: 180, |
|||
rules: [{ required: true, message: '请选择', trigger: ['blur', 'change'] }], |
|||
xType: 'select', |
|||
dic: [ |
|||
{ label: 'create', value: 'create' }, |
|||
{ label: 'assignment', value: 'assignment' }, |
|||
{ label: 'complete', value: 'complete' }, |
|||
{ label: 'delete', value: 'delete' } |
|||
], |
|||
tooltip: `create(创建):当任务已经创建,并且所有任务参数都已经设置时触发。<br /> |
|||
assignment(指派):当任务已经指派给某人时触发。请注意:当流程执行到达用户任务时,在触发create事件之前,会首先触发assignment事件。<br /> |
|||
complete(完成):当任务已经完成,从运行时数据中删除前触发。<br /> |
|||
delete(删除):在任务即将被删除前触发。请注意任务由completeTask正常完成时也会触发。 |
|||
` |
|||
}, |
|||
{ |
|||
label: '类型', |
|||
name: 'type', |
|||
width: 180, |
|||
rules: [{ required: true, message: '请选择', trigger: ['blur', 'change'] }], |
|||
xType: 'select', |
|||
dic: [ |
|||
{ label: '类', value: 'class' }, |
|||
{ label: '表达式', value: 'expression' }, |
|||
{ label: '委托表达式', value: 'delegateExpression' } |
|||
], |
|||
tooltip: `类:示例 com.company.MyCustomListener,自定义类必须实现 org.flowable.engine.delegate.TaskListener 接口 <br /> |
|||
表达式:示例 \${myObject.callMethod(task, task.eventName)} <br /> |
|||
委托表达式:示例 \${myListenerSpringBean} ,该 springBean 需要实现 org.flowable.engine.delegate.TaskListener 接口 |
|||
` |
|||
}, |
|||
{ |
|||
label: '值', |
|||
name: 'className', |
|||
xType: 'input', |
|||
rules: [{ required: true, message: '请输入', trigger: ['blur', 'change'] }] |
|||
}, |
|||
// { |
|||
// xType: 'slot', |
|||
// label: '参数', |
|||
// width: 120, |
|||
// slot: true, |
|||
// name: 'params' |
|||
// } |
|||
] |
|||
} |
|||
] |
|||
} |
|||
] |
|||
} |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.$nextTick(() => this.addButton()) |
|||
this.formData.taskListener = this.element.businessObject.extensionElements?.values |
|||
.filter(item => item.$type === 'flowable:TaskListener') |
|||
.map(item => { |
|||
let type |
|||
if ('class' in item) type = 'class' |
|||
if ('expression' in item) type = 'expression' |
|||
if ('delegateExpression' in item) type = 'delegateExpression' |
|||
return { |
|||
event: item.event, |
|||
type: type, |
|||
className: item[type], |
|||
params: item.fields?.map(field => { |
|||
let fieldType |
|||
if ('stringValue' in field) fieldType = 'stringValue' |
|||
if ('expression' in field) fieldType = 'expression' |
|||
return { |
|||
name: field.name, |
|||
type: fieldType, |
|||
value: field[fieldType] |
|||
} |
|||
}) ?? [] |
|||
} |
|||
}) ?? [] |
|||
}, |
|||
methods: { |
|||
addButton() { |
|||
const button = document.createElement('button') |
|||
button.innerText = '内置监听器' |
|||
button.setAttribute('type', 'button') |
|||
button.setAttribute('class', 'el-button el-button--primary el-button--mini') |
|||
button.addEventListener('click', () => this.listenerDialogVisible = true) |
|||
const div = document.getElementById('pane-taskListener') |
|||
const table = div.getElementsByClassName('el-table')[0] |
|||
div.insertBefore(button, table) |
|||
}, |
|||
configParam(index) { |
|||
this.nowIndex = index |
|||
const nowObj = this.formData.taskListener[index] |
|||
if (!nowObj.params) { |
|||
nowObj.params = [] |
|||
} |
|||
this.showParamDialog = true |
|||
}, |
|||
finishConfigParam(param) { |
|||
this.showParamDialog = false |
|||
// hack 数量不更新问题 |
|||
const cache = this.formData.taskListener[this.nowIndex] |
|||
cache.params = param |
|||
this.$set(this.formData.taskListener[this.nowIndex], this.nowIndex, cache) |
|||
this.nowIndex = null |
|||
}, |
|||
updateElement() { |
|||
if (this.formData.taskListener?.length) { |
|||
let extensionElements = this.element.businessObject.get('extensionElements') |
|||
if (!extensionElements) { |
|||
extensionElements = this.modeler.get('moddle').create('bpmn:ExtensionElements') |
|||
} |
|||
// 清除旧值 |
|||
extensionElements.values = extensionElements.values?.filter(item => item.$type !== 'flowable:TaskListener') ?? [] |
|||
this.formData.taskListener.forEach(item => { |
|||
const taskListener = this.modeler.get('moddle').create('flowable:TaskListener') |
|||
taskListener['event'] = item.event |
|||
taskListener[item.type] = item.className |
|||
if (item.params && item.params.length) { |
|||
item.params.forEach(field => { |
|||
const fieldElement = this.modeler.get('moddle').create('flowable:Field') |
|||
fieldElement['name'] = field.name |
|||
fieldElement[field.type] = field.value |
|||
// 注意:flowable.json 中定义的string和expression类为小写,不然会和原生的String类冲突,此处为hack |
|||
// const valueElement = this.modeler.get('moddle').create(`flowable:${field.type}`, { body: field.value }) |
|||
// fieldElement[field.type] = valueElement |
|||
taskListener.get('fields').push(fieldElement) |
|||
}) |
|||
} |
|||
extensionElements.get('values').push(taskListener) |
|||
}) |
|||
this.updateProperties({ extensionElements: extensionElements }) |
|||
} else { |
|||
const extensionElements = this.element.businessObject[`extensionElements`] |
|||
if (extensionElements) { |
|||
extensionElements.values = extensionElements.values?.filter(item => item.$type !== 'flowable:TaskListener') ?? [] |
|||
} |
|||
} |
|||
}, |
|||
closeDialog() { |
|||
this.$refs.xForm.validate().then(() => { |
|||
this.updateElement() |
|||
this.dialogVisible = false |
|||
}).catch(e => console.error(e)) |
|||
}, |
|||
addListener(data) { |
|||
this.formData.taskListener = this.formData.taskListener.concat(data) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
.flow-containers .el-badge__content.is-fixed { |
|||
top: 18px; |
|||
} |
|||
</style> |
|||
@ -1,105 +0,0 @@ |
|||
<template> |
|||
<div> |
|||
<x-form ref="xForm" v-model="formData" :config="formConfig"> |
|||
<template #executionListener> |
|||
<el-badge :value="executionListenerLength"> |
|||
<el-button size="small" @click="dialogName = 'executionListenerDialog'">编辑</el-button> |
|||
</el-badge> |
|||
</template> |
|||
</x-form> |
|||
<executionListenerDialog |
|||
v-if="dialogName === 'executionListenerDialog'" |
|||
:element="element" |
|||
:modeler="modeler" |
|||
@close="finishExecutionListener" |
|||
/> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import mixinPanel from '../../common/mixinPanel' |
|||
import {StrUtil} from '@/utils/StrUtil' |
|||
import mixinExecutionListener from '../../common/mixinExecutionListener' |
|||
import { commonParse, conditionExpressionParse } from '../../common/parseElement' |
|||
export default { |
|||
mixins: [mixinPanel, mixinExecutionListener], |
|||
data() { |
|||
return { |
|||
formData: {}, |
|||
executionListenerLength: 0 |
|||
} |
|||
}, |
|||
computed: { |
|||
formConfig() { |
|||
return { |
|||
inline: false, |
|||
item: [ |
|||
{ |
|||
xType: 'input', |
|||
name: 'id', |
|||
label: '节点 id', |
|||
rules: [{ required: true, message: 'Id 不能为空' }] |
|||
}, |
|||
{ |
|||
xType: 'input', |
|||
name: 'name', |
|||
label: '节点名称' |
|||
}, |
|||
{ |
|||
xType: 'input', |
|||
name: 'documentation', |
|||
label: '节点描述' |
|||
}, |
|||
{ |
|||
xType: 'slot', |
|||
name: 'executionListener', |
|||
label: '执行监听器' |
|||
}, |
|||
{ |
|||
xType: 'input', |
|||
name: 'conditionExpression', |
|||
label: '跳转条件' |
|||
}, |
|||
{ |
|||
xType: 'input', |
|||
name: 'skipExpression', |
|||
label: '跳过表达式' |
|||
} |
|||
] |
|||
} |
|||
} |
|||
}, |
|||
watch: { |
|||
'formData.conditionExpression': function(val) { |
|||
if (StrUtil.isNotBlank(val)) { |
|||
const newCondition = this.modeler.get('moddle').create('bpmn:FormalExpression', { body: val }) |
|||
this.updateProperties({ conditionExpression: newCondition }) |
|||
} |
|||
// else { |
|||
// this.updateProperties({ conditionExpression: null }) |
|||
// } |
|||
}, |
|||
'formData.skipExpression': function(val) { |
|||
if (StrUtil.isNotBlank(val)) { |
|||
this.updateProperties({'flowable:skipExpression': val}) |
|||
} else { |
|||
delete this.element.businessObject.$attrs[`flowable:skipExpression`] |
|||
} |
|||
} |
|||
}, |
|||
created() { |
|||
let cache = commonParse(this.element) |
|||
cache = conditionExpressionParse(cache) |
|||
this.formData = cache; |
|||
this.computedExecutionListenerLength(); |
|||
}, |
|||
methods:{ |
|||
computedExecutionListenerLength() { |
|||
this.executionListenerLength = this.element.businessObject.extensionElements?.values |
|||
?.filter(item => item.$type === 'flowable:ExecutionListener').length ?? 0 |
|||
}, |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style></style> |
|||
@ -1,102 +0,0 @@ |
|||
<template> |
|||
<div> |
|||
<x-form ref="xForm" v-model="formData" :config="formConfig"> |
|||
<template #executionListener> |
|||
<el-badge :value="executionListenerLength"> |
|||
<el-button size="small" @click="dialogName = 'executionListenerDialog'">编辑</el-button> |
|||
</el-badge> |
|||
</template> |
|||
</x-form> |
|||
<executionListenerDialog |
|||
v-if="dialogName === 'executionListenerDialog'" |
|||
:element="element" |
|||
:modeler="modeler" |
|||
@close="finishExecutionListener" |
|||
/> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import mixinPanel from '../../common/mixinPanel' |
|||
import mixinExecutionListener from '../../common/mixinExecutionListener' |
|||
import { commonParse } from '../../common/parseElement' |
|||
export default { |
|||
mixins: [mixinPanel, mixinExecutionListener], |
|||
data() { |
|||
return { |
|||
formData: {}, |
|||
executionListenerLength: 0 |
|||
} |
|||
}, |
|||
computed: { |
|||
formConfig() { |
|||
const _this = this |
|||
return { |
|||
inline: false, |
|||
item: [ |
|||
{ |
|||
xType: 'input', |
|||
name: 'id', |
|||
label: '节点 id', |
|||
rules: [{ required: true, message: 'Id 不能为空' }] |
|||
}, |
|||
{ |
|||
xType: 'input', |
|||
name: 'name', |
|||
label: '节点名称' |
|||
}, |
|||
{ |
|||
xType: 'input', |
|||
name: 'documentation', |
|||
label: '节点描述' |
|||
}, |
|||
{ |
|||
xType: 'slot', |
|||
name: 'executionListener', |
|||
label: '执行监听器' |
|||
}, |
|||
// { |
|||
// xType: 'input', |
|||
// name: 'initiator', |
|||
// label: '发起人', |
|||
// show: !!_this.showConfig.initiator |
|||
// }, |
|||
// { |
|||
// xType: 'input', |
|||
// name: 'formKey', |
|||
// label: '表单标识key', |
|||
// show: !!_this.showConfig.formKey |
|||
// } |
|||
] |
|||
} |
|||
} |
|||
}, |
|||
watch: { |
|||
'formData.initiator': function(val) { |
|||
if (val === '') val = null |
|||
// 默认设置流程发起人 |
|||
// if (val === '') val = 'INITIATOR' |
|||
this.updateProperties({ 'flowable:initiator': val }) |
|||
}, |
|||
'formData.formKey': function(val) { |
|||
if (val === '') val = null |
|||
this.updateProperties({ 'flowable:formKey': val }) |
|||
} |
|||
}, |
|||
created() { |
|||
// this.updateProperties({ 'flowable:initiator': 'INITIATOR' }) |
|||
this.formData = commonParse(this.element) |
|||
this.computedExecutionListenerLength(); |
|||
}, |
|||
methods:{ |
|||
computedExecutionListenerLength() { |
|||
this.executionListenerLength = this.element.businessObject.extensionElements?.values |
|||
?.filter(item => item.$type === 'flowable:ExecutionListener').length ?? 0 |
|||
}, |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
|
|||
</style> |
|||
@ -1,631 +0,0 @@ |
|||
<template> |
|||
<div> |
|||
<x-form ref="xForm" v-model="formData" :config="formConfig"> |
|||
<template #executionListener> |
|||
<el-badge :value="executionListenerLength"> |
|||
<el-button size="small" @click="dialogName = 'executionListenerDialog'">编辑</el-button> |
|||
</el-badge> |
|||
</template> |
|||
<template #taskListener> |
|||
<el-badge :value="taskListenerLength"> |
|||
<el-button size="small" @click="dialogName = 'taskListenerDialog'">编辑</el-button> |
|||
</el-badge> |
|||
</template> |
|||
<template #multiInstance> |
|||
<el-badge :is-dot="hasMultiInstance"> |
|||
<el-button size="small" @click="dialogName = 'multiInstanceDialog'">编辑</el-button> |
|||
</el-badge> |
|||
</template> |
|||
<template #checkSingleUser> |
|||
<el-input placeholder="请选择人员" class="input-with-select" v-model="checkValues"> |
|||
<template slot="append"> |
|||
<!--指定用户--> |
|||
<el-button style="padding-left: 7px" icon="el-icon-user" @click="singleUserCheck"/> |
|||
<el-divider direction="vertical"></el-divider> |
|||
<!--选择表达式--> |
|||
<el-button style="padding-right: 7px" icon="el-icon-postcard" @click="singleExpCheck('assignee')"/> |
|||
</template> |
|||
</el-input> |
|||
</template> |
|||
<template #checkMultipleUser> |
|||
<el-input placeholder="请选择候选用户" class="input-with-select" v-model="checkValues"> |
|||
<template slot="append"> |
|||
<!--候选用户--> |
|||
<el-button style="padding-left: 7px" icon="el-icon-user" @click="multipleUserCheck"/> |
|||
<el-divider direction="vertical"></el-divider> |
|||
<!--选择表达式--> |
|||
<el-button style="padding-right: 7px" icon="el-icon-postcard" @click="singleExpCheck('candidateUsers')"/> |
|||
</template> |
|||
</el-input> |
|||
</template> |
|||
<template #checkRole> |
|||
<el-input placeholder="请选择候选角色" class="input-with-select" v-model="checkValues"> |
|||
<template slot="append"> |
|||
<!--候选角色--> |
|||
<el-button style="padding-left: 7px" icon="el-icon-user" @click="multipleRoleCheck"/> |
|||
<el-divider direction="vertical"></el-divider> |
|||
<!--选择表达式--> |
|||
<el-button style="padding-right: 7px" icon="el-icon-postcard" @click="singleExpCheck('candidateGroups')"/> |
|||
</template> |
|||
</el-input> |
|||
</template> |
|||
</x-form> |
|||
<executionListenerDialog |
|||
v-if="dialogName === 'executionListenerDialog'" |
|||
:element="element" |
|||
:modeler="modeler" |
|||
@close="finishExecutionListener" |
|||
/> |
|||
<taskListenerDialog |
|||
v-if="dialogName === 'taskListenerDialog'" |
|||
:element="element" |
|||
:modeler="modeler" |
|||
@close="finishTaskListener" |
|||
/> |
|||
<multiInstanceDialog |
|||
v-if="dialogName === 'multiInstanceDialog'" |
|||
:element="element" |
|||
:modeler="modeler" |
|||
@close="finishMultiInstance" |
|||
/> |
|||
<!--选择人员--> |
|||
<el-dialog |
|||
title="选择人员" |
|||
:visible.sync="userVisible" |
|||
width="60%" |
|||
:close-on-press-escape="false" |
|||
:show-close="false" |
|||
> |
|||
<flow-user :checkType="checkType" :selectValues="selectValues" @handleUserSelect="handleUserSelect"></flow-user> |
|||
<span slot="footer" class="dialog-footer"> |
|||
<el-button @click="userVisible = false">取 消</el-button> |
|||
<el-button type="primary" @click="checkUserComplete">确 定</el-button> |
|||
</span> |
|||
</el-dialog> |
|||
<!--选择表达式--> |
|||
<el-dialog |
|||
title="选择表达式" |
|||
:visible.sync="expVisible" |
|||
width="60%" |
|||
:close-on-press-escape="false" |
|||
:show-close="false" |
|||
> |
|||
<flow-exp :selectValues="selectValues" @handleSingleExpSelect="handleSingleExpSelect"></flow-exp> |
|||
<span slot="footer" class="dialog-footer"> |
|||
<el-button @click="expVisible = false">取 消</el-button> |
|||
<el-button type="primary" @click="checkExpComplete">确 定</el-button> |
|||
</span> |
|||
</el-dialog> |
|||
<!--选择角色--> |
|||
<el-dialog |
|||
title="选择候选角色" |
|||
:visible.sync="roleVisible" |
|||
width="60%" |
|||
:close-on-press-escape="false" |
|||
:show-close="false" |
|||
> |
|||
<flow-role :checkType="checkType" :selectValues="selectValues" @handleRoleSelect="handleRoleSelect"></flow-role> |
|||
<span slot="footer" class="dialog-footer"> |
|||
<el-button @click="roleVisible = false">取 消</el-button> |
|||
<el-button type="primary" @click="checkRoleComplete">确 定</el-button> |
|||
</span> |
|||
</el-dialog> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import mixinPanel from '../../common/mixinPanel' |
|||
import executionListenerDialog from './property/executionListener' |
|||
import taskListenerDialog from './property/taskListener' |
|||
import multiInstanceDialog from './property/multiInstance' |
|||
import { commonParse, userTaskParse } from '../../common/parseElement' |
|||
import {StrUtil} from '@/utils/StrUtil' |
|||
import FlowUser from '@/components/flow/User' |
|||
import FlowRole from '@/components/flow/Role' |
|||
import FlowExp from '@/components/flow/Expression' |
|||
import { listAllForm } from '@/api/flowable/form' |
|||
|
|||
export default { |
|||
components: { |
|||
executionListenerDialog, |
|||
taskListenerDialog, |
|||
multiInstanceDialog, |
|||
FlowUser, |
|||
FlowRole, |
|||
FlowExp, |
|||
}, |
|||
mixins: [mixinPanel], |
|||
props: { |
|||
users: { |
|||
type: Array, |
|||
required: true |
|||
}, |
|||
groups: { |
|||
type: Array, |
|||
required: true |
|||
}, |
|||
exps: { |
|||
type: Array, |
|||
required: true |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
userTypeOption: [ |
|||
{ label: '指定人员', value: 'assignee' }, |
|||
{ label: '候选人员', value: 'candidateUsers' }, |
|||
{ label: '候选角色', value: 'candidateGroups' } |
|||
], |
|||
dialogName: '', |
|||
executionListenerLength: 0, |
|||
taskListenerLength: 0, |
|||
hasMultiInstance: false, |
|||
userVisible: false, |
|||
roleVisible: false, |
|||
expVisible: false, |
|||
formData: {}, |
|||
assignee: null, |
|||
candidateUsers: null, |
|||
candidateGroups: null, |
|||
// 选类型 |
|||
checkType: 'single', |
|||
// 选中的值 |
|||
checkValues: null, |
|||
// 数据回显 |
|||
selectValues: null, |
|||
// 用户列表 |
|||
userList: this.users, |
|||
// 角色列表 |
|||
groupList: this.groups, |
|||
// 表达式列表 |
|||
expList: this.exps, |
|||
// 表达式类型 |
|||
expType: null, |
|||
// 表单列表 |
|||
formList: [], |
|||
} |
|||
}, |
|||
computed: { |
|||
formConfig() { |
|||
const _this = this |
|||
return { |
|||
inline: false, |
|||
item: [ |
|||
{ |
|||
xType: 'input', |
|||
name: 'id', |
|||
label: '节点 id', |
|||
rules: [{ required: true, message: 'Id 不能为空' }] |
|||
}, |
|||
{ |
|||
xType: 'input', |
|||
name: 'name', |
|||
label: '节点名称', |
|||
rules: [{ required: true, message: '节点名称不能为空' }] |
|||
}, |
|||
{ |
|||
xType: 'input', |
|||
name: 'documentation', |
|||
label: '节点描述' |
|||
}, |
|||
{ |
|||
xType: 'slot', |
|||
name: 'executionListener', |
|||
label: '执行监听器' |
|||
}, |
|||
{ |
|||
xType: 'slot', |
|||
name: 'taskListener', |
|||
label: '任务监听器', |
|||
show: !!_this.showConfig.taskListener |
|||
}, |
|||
{ |
|||
xType: 'select', |
|||
name: 'userType', |
|||
label: '用户类型', |
|||
// clearable: true, |
|||
dic: _this.userTypeOption, |
|||
// rules: [{ required: true, message: '用户类型不能为空' }], |
|||
show: !!_this.showConfig.userType |
|||
}, |
|||
{ |
|||
xType: 'slot', |
|||
name: 'checkSingleUser', |
|||
label: '指定人员', |
|||
// rules: [{ required: true, message: '指定人员不能为空' }], |
|||
show: !!_this.showConfig.assignee && _this.formData.userType === 'assignee' |
|||
}, |
|||
{ |
|||
xType: 'slot', |
|||
name: 'checkMultipleUser', |
|||
label: '候选人员', |
|||
// rules: [{ required: true, message: '候选人员不能为空' }], |
|||
show: !!_this.showConfig.candidateUsers && _this.formData.userType === 'candidateUsers' |
|||
}, |
|||
{ |
|||
xType: 'slot', |
|||
name: 'checkRole', |
|||
label: '候选角色', |
|||
// rules: [{ required: true, message: '候选角色不能为空' }], |
|||
show: !!_this.showConfig.candidateGroups && _this.formData.userType === 'candidateGroups' |
|||
}, |
|||
{ |
|||
xType: 'slot', |
|||
name: 'multiInstance', |
|||
label: '多实例' |
|||
}, |
|||
{ |
|||
xType: 'switch', |
|||
name: 'async', |
|||
label: '异步', |
|||
activeText: '是', |
|||
inactiveText: '否', |
|||
show: !!_this.showConfig.async |
|||
}, |
|||
{ |
|||
xType: 'input', |
|||
name: 'priority', |
|||
label: '优先级', |
|||
show: !!_this.showConfig.priority |
|||
}, |
|||
// { |
|||
// xType: 'input', |
|||
// name: 'formKey', |
|||
// label: '表单标识key', |
|||
// show: !!_this.showConfig.formKey |
|||
// }, |
|||
{ |
|||
xType: 'select', |
|||
name: 'formKey', |
|||
label: '表单标识key', |
|||
clearable: true, |
|||
dic: { data: _this.formList, label: 'formName', value: 'formId' }, |
|||
show: !!_this.showConfig.formKey |
|||
}, |
|||
{ |
|||
xType: 'input', |
|||
name: 'skipExpression', |
|||
label: '跳过表达式', |
|||
show: !!_this.showConfig.skipExpression |
|||
}, |
|||
{ |
|||
xType: 'switch', |
|||
name: 'isForCompensation', |
|||
label: '是否为补偿', |
|||
activeText: '是', |
|||
inactiveText: '否', |
|||
show: !!_this.showConfig.isForCompensation |
|||
}, |
|||
{ |
|||
xType: 'switch', |
|||
name: 'triggerable', |
|||
label: '服务任务可触发', |
|||
activeText: '是', |
|||
inactiveText: '否', |
|||
show: !!_this.showConfig.triggerable |
|||
}, |
|||
{ |
|||
xType: 'switch', |
|||
name: 'autoStoreVariables', |
|||
label: '自动存储变量', |
|||
activeText: '是', |
|||
inactiveText: '否', |
|||
show: !!_this.showConfig.autoStoreVariables |
|||
}, |
|||
{ |
|||
xType: 'input', |
|||
name: 'ruleVariablesInput', |
|||
label: '输入变量', |
|||
show: !!_this.showConfig.ruleVariablesInput |
|||
}, |
|||
{ |
|||
xType: 'input', |
|||
name: 'rules', |
|||
label: '规则', |
|||
show: !!_this.showConfig.rules |
|||
}, |
|||
{ |
|||
xType: 'input', |
|||
name: 'resultVariable', |
|||
label: '结果变量', |
|||
show: !!_this.showConfig.resultVariable |
|||
}, |
|||
{ |
|||
xType: 'switch', |
|||
name: 'exclude', |
|||
label: '排除', |
|||
activeText: '是', |
|||
inactiveText: '否', |
|||
show: !!_this.showConfig.exclude |
|||
}, |
|||
{ |
|||
xType: 'input', |
|||
name: 'class', |
|||
label: '类', |
|||
show: !!_this.showConfig.class |
|||
}, |
|||
{ |
|||
xType: 'datePicker', |
|||
type: 'datetime', |
|||
valueFormat: 'yyyy-MM-ddTHH:mm:ss', |
|||
name: 'dueDate', |
|||
label: '到期时间', |
|||
show: !!_this.showConfig.dueDate |
|||
} |
|||
] |
|||
} |
|||
} |
|||
}, |
|||
watch: { |
|||
'formData.userType': function(val, oldVal) { |
|||
if (StrUtil.isNotBlank(oldVal)) { |
|||
delete this.element.businessObject.$attrs[`flowable:${oldVal}`] |
|||
delete this.formData[oldVal] |
|||
// 清除已选人员数据 |
|||
this.checkValues = ''; |
|||
this.selectValues = null; |
|||
// 删除xml中已选择数据类型节点 |
|||
delete this.element.businessObject.$attrs[`flowable:dataType`] |
|||
} |
|||
// 写入userType节点信息到xml |
|||
this.updateProperties({'flowable:userType': val}) |
|||
}, |
|||
'formData.async': function(val) { |
|||
if (StrUtil.isNotBlank(val)) { |
|||
this.updateProperties({'flowable:async': val}) |
|||
} |
|||
}, |
|||
'formData.dueDate': function(val) { |
|||
if (StrUtil.isNotBlank(val)) { |
|||
this.updateProperties({'flowable:dueDate': val}) |
|||
} |
|||
}, |
|||
'formData.formKey': function(val) { |
|||
if (StrUtil.isNotBlank(val)) { |
|||
this.updateProperties({'flowable:formKey': val}) |
|||
} else { |
|||
// 删除xml中已选择表单信息 |
|||
delete this.element.businessObject[`formKey`] |
|||
} |
|||
}, |
|||
'formData.priority': function(val) { |
|||
if (StrUtil.isNotBlank(val)) { |
|||
this.updateProperties({'flowable:priority': val}) |
|||
} |
|||
}, |
|||
'formData.skipExpression': function(val) { |
|||
if (StrUtil.isNotBlank(val)) { |
|||
this.updateProperties({'flowable:skipExpression': val}) |
|||
} else { |
|||
delete this.element.businessObject.$attrs[`flowable:skipExpression`] |
|||
} |
|||
}, |
|||
'formData.isForCompensation': function(val) { |
|||
if (StrUtil.isNotBlank(val)) { |
|||
this.updateProperties({'isForCompensation': val}) |
|||
} |
|||
}, |
|||
'formData.triggerable': function(val) { |
|||
if (StrUtil.isNotBlank(val)) { |
|||
this.updateProperties({'flowable:triggerable': val}) |
|||
} |
|||
}, |
|||
'formData.class': function(val) { |
|||
if (StrUtil.isNotBlank(val)) { |
|||
this.updateProperties({'flowable:class': val}) |
|||
} |
|||
}, |
|||
'formData.autoStoreVariables': function(val) { |
|||
if (StrUtil.isNotBlank(val)) { |
|||
this.updateProperties({'flowable:autoStoreVariables': val}) |
|||
} |
|||
}, |
|||
'formData.exclude': function(val) { |
|||
if (StrUtil.isNotBlank(val)) { |
|||
this.updateProperties({'flowable:exclude': val}) |
|||
} |
|||
}, |
|||
'formData.ruleVariablesInput': function(val) { |
|||
if (StrUtil.isNotBlank(val)) { |
|||
this.updateProperties({'flowable:ruleVariablesInput': val}) |
|||
} |
|||
}, |
|||
'formData.rules': function(val) { |
|||
if (StrUtil.isNotBlank(val)) { |
|||
this.updateProperties({'flowable:rules': val}) |
|||
} |
|||
}, |
|||
'formData.resultVariable': function(val) { |
|||
if (StrUtil.isNotBlank(val)) { |
|||
this.updateProperties({'flowable:resultVariable': val}) |
|||
} |
|||
} |
|||
}, |
|||
created() { |
|||
let cache = commonParse(this.element) |
|||
cache = userTaskParse(cache) |
|||
this.formData = cache |
|||
this.computedExecutionListenerLength() |
|||
this.computedTaskListenerLength() |
|||
this.computedHasMultiInstance() |
|||
// 人员信息回显 |
|||
this.checkValuesEcho(); |
|||
// 加载表单列表 |
|||
this.getListForm(); |
|||
}, |
|||
methods: { |
|||
computedExecutionListenerLength() { |
|||
this.executionListenerLength = this.element.businessObject.extensionElements?.values |
|||
?.filter(item => item.$type === 'flowable:ExecutionListener').length ?? 0 |
|||
}, |
|||
computedTaskListenerLength() { |
|||
this.taskListenerLength = this.element.businessObject.extensionElements?.values |
|||
?.filter(item => item.$type === 'flowable:TaskListener').length ?? 0 |
|||
}, |
|||
computedHasMultiInstance() { |
|||
if (this.element.businessObject.loopCharacteristics) { |
|||
this.hasMultiInstance = true |
|||
} else { |
|||
this.hasMultiInstance = false |
|||
} |
|||
}, |
|||
// 获取表单信息 |
|||
getListForm(){ |
|||
listAllForm().then(res =>{ |
|||
res.data.forEach(item =>{ |
|||
item.formId = item.formId.toString(); |
|||
}) |
|||
this.formList = res.data; |
|||
}) |
|||
}, |
|||
// 设计器右侧表单数据回显 |
|||
checkValuesEcho(){ |
|||
const that = this; |
|||
const attrs = that.element.businessObject.$attrs; |
|||
const businessObject = that.element.businessObject; |
|||
console.log(that.element.businessObject,"this.element.businessObject") |
|||
// 指定用户 |
|||
if (attrs.hasOwnProperty("flowable:assignee")) { |
|||
const val = attrs["flowable:assignee"]; |
|||
// 查找是否动态指定人员(选中流程表达式) |
|||
if (attrs["flowable:dataType"] === "dynamic") { |
|||
this.checkValues = that.expList.find(item => item.expression == val).name; |
|||
this.selectValues = that.expList.find(item => item.expression == val).id; |
|||
} else { |
|||
this.checkValues = that.userList.find(item => item.userId == val).nickName; |
|||
this.selectValues = that.userList.find(item => item.userId == val).userId; |
|||
} |
|||
// 候选用户 |
|||
} else if (attrs.hasOwnProperty("flowable:candidateUsers")) { |
|||
const val = attrs["flowable:candidateUsers"]; |
|||
if (attrs["flowable:dataType"] === "dynamic") { |
|||
this.checkValues = that.expList.find(item => item.expression == val).name; |
|||
this.selectValues = that.expList.find(item => item.expression == val).id; |
|||
} else { |
|||
const newArr = that.userList.filter(i => val.split(',').includes(i.userId)) |
|||
this.checkValues = newArr.map(item => item.nickName).join(','); |
|||
this.selectValues = newArr.map(item => item.userId).join(','); |
|||
} |
|||
} else if (businessObject.hasOwnProperty("candidateGroups") || attrs.hasOwnProperty("flowable:candidateGroups") ) { |
|||
// 候选角色信息 |
|||
const val = businessObject["candidateGroups"] || attrs["flowable:candidateGroups"]; |
|||
if (attrs["flowable:dataType"] === "dynamic") { |
|||
this.checkValues = that.expList.find(item => item.expression == val).name; |
|||
this.selectValues = that.expList.find(item => item.expression == val).id; |
|||
} else { |
|||
const newArr = that.groupList.filter(i => val.split(',').includes(i.roleId)) |
|||
this.checkValues = newArr.map(item => item.roleName).join(','); |
|||
this.selectValues = newArr.map(item => item.roleId).join(','); |
|||
} |
|||
} |
|||
}, |
|||
finishExecutionListener() { |
|||
if (this.dialogName === 'executionListenerDialog') { |
|||
this.computedExecutionListenerLength() |
|||
} |
|||
this.dialogName = '' |
|||
}, |
|||
finishTaskListener() { |
|||
if (this.dialogName === 'taskListenerDialog') { |
|||
this.computedTaskListenerLength() |
|||
} |
|||
this.dialogName = '' |
|||
}, |
|||
finishMultiInstance() { |
|||
if (this.dialogName === 'multiInstanceDialog') { |
|||
this.computedHasMultiInstance() |
|||
} |
|||
this.dialogName = '' |
|||
}, |
|||
/*单选人员*/ |
|||
singleUserCheck(){ |
|||
this.userVisible = true; |
|||
this.checkType = "single"; |
|||
}, |
|||
/*多选人员*/ |
|||
multipleUserCheck(){ |
|||
this.userVisible = true; |
|||
this.checkType = "multiple"; |
|||
}, |
|||
/*单选角色*/ |
|||
singleRoleCheck(){ |
|||
this.roleVisible = true; |
|||
this.checkType = "single"; |
|||
}, |
|||
/*多选角色*/ |
|||
multipleRoleCheck(){ |
|||
this.roleVisible = true; |
|||
this.checkType = "multiple"; |
|||
}, |
|||
/*单选表达式*/ |
|||
singleExpCheck(expType){ |
|||
this.expVisible = true; |
|||
this.expType = expType; |
|||
}, |
|||
// 选中表达式 |
|||
handleSingleExpSelect(selection) { |
|||
this.deleteFlowAttar(); |
|||
this.updateProperties({'flowable:dataType': 'dynamic'}) |
|||
if ("assignee" === this.expType) { |
|||
this.updateProperties({'flowable:assignee': selection.expression}); |
|||
} else if ("candidateUsers" === this.expType) { |
|||
this.updateProperties({'flowable:candidateUsers': selection.expression}); |
|||
} else if ("candidateGroups" === this.expType) { |
|||
this.updateProperties({'flowable:candidateGroups': selection.expression}); |
|||
} |
|||
this.checkValues = selection.name; |
|||
this.expType = null; |
|||
}, |
|||
// 用户选中数据 |
|||
handleUserSelect(selection) { |
|||
const that = this; |
|||
if (selection) { |
|||
that.deleteFlowAttar(); |
|||
that.updateProperties({'flowable:dataType': 'fixed'}) |
|||
if (selection instanceof Array) { |
|||
const userIds = selection.map(item => item.userId); |
|||
const nickName = selection.map(item => item.nickName); |
|||
that.updateProperties({'flowable:candidateUsers': userIds.join(',')}) |
|||
that.checkValues = nickName.join(','); |
|||
} else { |
|||
that.updateProperties({'flowable:assignee': selection.userId}) |
|||
that.checkValues = selection.nickName; |
|||
} |
|||
} |
|||
}, |
|||
// 角色选中数据 |
|||
handleRoleSelect(selection, name) { |
|||
const that = this; |
|||
if (selection && name) { |
|||
that.deleteFlowAttar(); |
|||
that.updateProperties({'flowable:dataType': 'fixed'}) |
|||
that.updateProperties({'flowable:candidateGroups': selection}); |
|||
that.checkValues = name; |
|||
} |
|||
}, |
|||
/*用户选中赋值*/ |
|||
checkUserComplete(){ |
|||
this.userVisible = false; |
|||
this.checkType = ""; |
|||
}, |
|||
/*候选角色选中赋值*/ |
|||
checkRoleComplete(){ |
|||
this.roleVisible = false; |
|||
this.checkType = ""; |
|||
}, |
|||
/*表达式选中赋值*/ |
|||
checkExpComplete(){ |
|||
this.expVisible = false; |
|||
}, |
|||
// 删除节点 |
|||
deleteFlowAttar(){ |
|||
delete this.element.businessObject.$attrs[`flowable:dataType`] |
|||
delete this.element.businessObject.$attrs[`flowable:assignee`] |
|||
delete this.element.businessObject.$attrs[`flowable:candidateUsers`] |
|||
delete this.element.businessObject.$attrs[`flowable:candidateGroups`] |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style></style> |
|||
@ -0,0 +1,187 @@ |
|||
<template> |
|||
<div> |
|||
<template slot="header"> |
|||
<div class="card-header"> |
|||
<span>{{ translateNodeName(elementType) }}</span> |
|||
</div> |
|||
</template> |
|||
<el-collapse v-model="activeName" > |
|||
<!-- 常规信息 --> |
|||
<el-collapse-item name="common"> |
|||
<template slot="title"><i class="el-icon-info"></i> 常规信息</template> |
|||
<common-panel :id="elementId"/> |
|||
</el-collapse-item> |
|||
|
|||
<!-- 任务信息 --> |
|||
<el-collapse-item name="Task" v-if="elementType.indexOf('Task') !== -1"> |
|||
<template slot="title"><i class="el-icon-s-claim"></i> 任务配置</template> |
|||
<user-task-panel :id="elementId"/> |
|||
</el-collapse-item> |
|||
|
|||
<!-- 表单 --> |
|||
<el-collapse-item name="form" v-if="formVisible"> |
|||
<template slot="title"><i class="el-icon-s-order"></i> 表单配置</template> |
|||
<form-panel :id="elementId"/> |
|||
</el-collapse-item> |
|||
|
|||
<!-- 执行监听器 --> |
|||
<el-collapse-item name="executionListener"> |
|||
<template slot="title"><i class="el-icon-s-promotion"></i> 执行监听器 |
|||
<el-badge :value="executionListenerCount" class="item" type="primary"/> |
|||
</template> |
|||
<execution-listener :id="elementId" @getExecutionListenerCount="getExecutionListenerCount"/> |
|||
</el-collapse-item> |
|||
|
|||
<!-- 任务监听器 --> |
|||
<el-collapse-item name="taskListener" v-if="elementType === 'UserTask'" > |
|||
<template slot="title"><i class="el-icon-s-flag"></i> 任务监听器 |
|||
<el-badge :value="taskListenerCount" class="item" type="primary"/> |
|||
</template> |
|||
<task-listener :id="elementId" @getTaskListenerCount="getTaskListenerCount"/> |
|||
</el-collapse-item> |
|||
|
|||
<!-- 多实例 --> |
|||
<el-collapse-item name="multiInstance" v-if="elementType.indexOf('Task') !== -1" > |
|||
<template slot="title"><i class="el-icon-s-grid"></i> 多实例</template> |
|||
<multi-instance :id="elementId"/> |
|||
</el-collapse-item> |
|||
<!-- 流转条件 --> |
|||
<el-collapse-item name="condition" v-if="conditionVisible" > |
|||
<template slot="title"><i class="el-icon-share"></i> 流转条件</template> |
|||
<condition-panel :id="elementId"/> |
|||
</el-collapse-item> |
|||
|
|||
<!-- 扩展属性 --> |
|||
<el-collapse-item name="properties" > |
|||
<template slot="title"><i class="el-icon-circle-plus"></i> 扩展属性</template> |
|||
<properties-panel :id="elementId"/> |
|||
</el-collapse-item> |
|||
|
|||
</el-collapse> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import ExecutionListener from './panel/executionListener' |
|||
import TaskListener from './panel/taskListener' |
|||
import MultiInstance from './panel/multiInstance' |
|||
import CommonPanel from './panel/commonPanel' |
|||
import UserTaskPanel from './panel/taskPanel' |
|||
import ConditionPanel from './panel/conditionPanel' |
|||
import FormPanel from './panel/formPanel' |
|||
import OtherPanel from './panel/otherPanel' |
|||
import PropertiesPanel from './panel/PropertiesPanel' |
|||
|
|||
import { translateNodeName } from "./common/bpmnUtils"; |
|||
import FlowUser from "@/components/flow/User/index.vue"; |
|||
import FlowRole from "@/components/flow/Role/index.vue"; |
|||
import FlowExp from "@/components/flow/Expression/index.vue"; |
|||
export default { |
|||
name: "Designer", |
|||
components: { |
|||
ExecutionListener, |
|||
TaskListener, |
|||
MultiInstance, |
|||
CommonPanel, |
|||
UserTaskPanel, |
|||
ConditionPanel, |
|||
FormPanel, |
|||
OtherPanel, |
|||
PropertiesPanel, |
|||
FlowUser, |
|||
FlowRole, |
|||
FlowExp, |
|||
}, |
|||
data() { |
|||
return { |
|||
activeName : 'common', |
|||
executionListenerCount: 0, |
|||
taskListenerCount:0, |
|||
elementId:"", |
|||
elementType:"", |
|||
conditionVisible:false,// 流转条件设置 |
|||
formVisible:false, // 表单配置 |
|||
rules:{ |
|||
id: [ |
|||
{ required: true, message: '节点Id 不能为空', trigger: 'blur' }, |
|||
], |
|||
name: [ |
|||
{ required: true, message: '节点名称不能为空', trigger: 'blur' }, |
|||
], |
|||
}, |
|||
} |
|||
}, |
|||
|
|||
/** 传值监听 */ |
|||
watch: { |
|||
elementId: { |
|||
handler() { |
|||
this.activeName = "common"; |
|||
} |
|||
}, |
|||
}, |
|||
created() { |
|||
this.initModels(); |
|||
}, |
|||
methods: { |
|||
// 初始化流程设计器 |
|||
initModels() { |
|||
this.getActiveElement(); |
|||
}, |
|||
|
|||
// 注册节点事件 |
|||
getActiveElement() { |
|||
// 初始第一个选中元素 bpmn:Process |
|||
this.initFormOnChanged(null); |
|||
this.modelerStore.modeler.on("import.done", e => { |
|||
this.initFormOnChanged(null); |
|||
}); |
|||
// 监听选择事件,修改当前激活的元素以及表单 |
|||
this.modelerStore.modeler.on("selection.changed", ({newSelection}) => { |
|||
this.initFormOnChanged(newSelection[0] || null); |
|||
}); |
|||
this.modelerStore.modeler.on("element.changed", ({element}) => { |
|||
// 保证 修改 "默认流转路径" 类似需要修改多个元素的事件发生的时候,更新表单的元素与原选中元素不一致。 |
|||
if (element && element.id === this.elementId) { |
|||
this.initFormOnChanged(element); |
|||
} |
|||
}); |
|||
}, |
|||
|
|||
// 初始化数据 |
|||
initFormOnChanged(element) { |
|||
let activatedElement = element; |
|||
if (!activatedElement) { |
|||
activatedElement = |
|||
this.modelerStore.elRegistry.find(el => el.type === "bpmn:Process") ?? |
|||
this.modelerStore.elRegistry.find(el => el.type === "bpmn:Collaboration"); |
|||
} |
|||
if (!activatedElement) return; |
|||
this.modelerStore.element = activatedElement; |
|||
this.elementId = activatedElement.id; |
|||
this.elementType = activatedElement.type.split(":")[1] || ""; |
|||
this.conditionVisible = !!( |
|||
this.elementType === "SequenceFlow" && |
|||
activatedElement.source && |
|||
activatedElement.source.type.indexOf("StartEvent") === -1 |
|||
); |
|||
this.formVisible = this.elementType === "UserTask" || this.elementType === "StartEvent"; |
|||
}, |
|||
|
|||
/** 获取执行监听器数量 */ |
|||
getExecutionListenerCount(value) { |
|||
this.executionListenerCount = value; |
|||
}, |
|||
/** 获取任务监听器数量 */ |
|||
getTaskListenerCount(value) { |
|||
this.taskListenerCount = value; |
|||
}, |
|||
translateNodeName(val){ |
|||
return translateNodeName(val); |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss"> |
|||
</style> |
|||
@ -1,51 +0,0 @@ |
|||
export default { |
|||
'bpmn:EndEvent': {}, |
|||
'bpmn:StartEvent': { |
|||
initiator: true, |
|||
formKey: true |
|||
}, |
|||
'bpmn:UserTask': { |
|||
userType: true, |
|||
assignee: true, |
|||
candidateUsers: true, |
|||
candidateGroups: true, |
|||
async: true, |
|||
priority: true, |
|||
formKey: true, |
|||
skipExpression: true, |
|||
dueDate: true, |
|||
taskListener: true |
|||
}, |
|||
'bpmn:ServiceTask': { |
|||
async: true, |
|||
skipExpression: true, |
|||
isForCompensation: true, |
|||
triggerable: true, |
|||
class: true |
|||
}, |
|||
'bpmn:ScriptTask': { |
|||
async: true, |
|||
isForCompensation: true, |
|||
autoStoreVariables: true |
|||
}, |
|||
'bpmn:ManualTask': { |
|||
async: true, |
|||
isForCompensation: true |
|||
}, |
|||
'bpmn:ReceiveTask': { |
|||
async: true, |
|||
isForCompensation: true |
|||
}, |
|||
'bpmn:SendTask': { |
|||
async: true, |
|||
isForCompensation: true |
|||
}, |
|||
'bpmn:BusinessRuleTask': { |
|||
async: true, |
|||
isForCompensation: true, |
|||
ruleVariablesInput: true, |
|||
rules: true, |
|||
resultVariable: true, |
|||
exclude: true |
|||
} |
|||
} |
|||
@ -1,5 +0,0 @@ |
|||
import workflowBpmnModeler from './index.vue' |
|||
|
|||
workflowBpmnModeler.install = Vue => Vue.component(workflowBpmnModeler.name, workflowBpmnModeler) // 给组件配置install方法
|
|||
|
|||
export default workflowBpmnModeler |
|||
@ -0,0 +1,140 @@ |
|||
<template> |
|||
<div class="panel-tab__content"> |
|||
<el-divider content-position="center">按钮设置</el-divider> |
|||
<el-table :data="elementButtonList" size="mini" max-height="240" border fit> |
|||
<el-table-column label="序号" width="50px" type="index" /> |
|||
<el-table-column label="属性名" prop="name" min-width="100px" show-overflow-tooltip /> |
|||
<el-table-column label="属性值" prop="value" min-width="100px" show-overflow-tooltip /> |
|||
<el-table-column label="操作" width="90px"> |
|||
<template slot-scope="{ row, $index }"> |
|||
<el-button size="mini" type="text" @click="openAttributesForm(row, $index)">编辑</el-button> |
|||
<el-divider direction="vertical" /> |
|||
<el-button size="mini" type="text" style="color: #ff4d4f" @click="removeAttributes(row, $index)">移除</el-button> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
<div class="element-drawer__button_save"> |
|||
<el-button size="mini" type="primary" icon="el-icon-plus" @click="openAttributesForm(null, -1)">添加按钮</el-button> |
|||
</div> |
|||
|
|||
<el-dialog :visible.sync="buttonFormModelVisible" title="按钮配置" width="600px" append-to-body destroy-on-close> |
|||
<el-form :model="buttonForm" label-width="80px" size="mini" ref="attributeFormRef" @submit.native.prevent> |
|||
<el-form-item label="属性名:" prop="label"> |
|||
<el-input v-model="buttonForm.label" clearable /> |
|||
</el-form-item> |
|||
<el-form-item label="属性值:" prop="value"> |
|||
<el-input v-model="buttonForm.value" clearable /> |
|||
</el-form-item> |
|||
</el-form> |
|||
<template slot="footer"> |
|||
<el-button size="mini" @click="buttonFormModelVisible = false">取 消</el-button> |
|||
<el-button size="mini" type="primary" @click="saveAttribute">确 定</el-button> |
|||
</template> |
|||
</el-dialog> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import {StrUtil} from "@/utils/StrUtil"; |
|||
|
|||
export default { |
|||
name: "ButtonsPanel", |
|||
props: { |
|||
id: { |
|||
type: String, |
|||
required: true |
|||
}, |
|||
}, |
|||
data() { |
|||
return { |
|||
elementButtonList: [], |
|||
otherExtensionList: [], |
|||
buttonForm: {}, |
|||
editingPropertyIndex: -1, |
|||
buttonFormModelVisible: false |
|||
}; |
|||
}, |
|||
watch: { |
|||
id: { |
|||
immediate: true, |
|||
handler(val) { |
|||
if (StrUtil.isNotBlank(val)) { |
|||
this.resetAttributesList(); |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
methods: { |
|||
resetAttributesList() { |
|||
this.bpmnElement = this.modelerStore.element; |
|||
this.otherExtensionList = []; // 其他扩展配置 |
|||
this.bpmnElementProperties = |
|||
this.bpmnElement.businessObject?.extensionElements?.values?.filter(ex => { |
|||
if (ex.$type !== `flowable:Buttons`) { |
|||
this.otherExtensionList.push(ex); |
|||
} |
|||
return ex.$type === `flowable:Buttons`; |
|||
}) ?? []; |
|||
|
|||
// 保存所有的 扩展属性字段 |
|||
this.bpmnElementButtonList = this.bpmnElementProperties.reduce((pre, current) => pre.concat(current.values), []); |
|||
// 复制 显示 |
|||
this.elementButtonList = JSON.parse(JSON.stringify(this.bpmnElementButtonList ?? [])); |
|||
}, |
|||
openAttributesForm(attr, index) { |
|||
this.editingPropertyIndex = index; |
|||
this.buttonForm = index === -1 ? {} : JSON.parse(JSON.stringify(attr)); |
|||
this.buttonFormModelVisible = true; |
|||
this.$nextTick(() => { |
|||
if (this.$refs["attributeFormRef"]) this.$refs["attributeFormRef"].clearValidate(); |
|||
}); |
|||
}, |
|||
removeAttributes(attr, index) { |
|||
this.$confirm("确认移除该属性吗?", "提示", { |
|||
confirmButtonText: "确 认", |
|||
cancelButtonText: "取 消" |
|||
}) |
|||
.then(() => { |
|||
this.elementButtonList.splice(index, 1); |
|||
this.bpmnElementButtonList.splice(index, 1); |
|||
// 新建一个属性字段的保存列表 |
|||
const propertiesObject = this.modelerStore.moddle.create(`flowable:Properties`, { |
|||
values: this.bpmnElementButtonList |
|||
}); |
|||
this.updateElementExtensions(propertiesObject); |
|||
this.resetAttributesList(); |
|||
}) |
|||
.catch(() => console.info("操作取消")); |
|||
}, |
|||
saveAttribute() { |
|||
const { name, value } = this.buttonForm; |
|||
console.log(this.bpmnElementButtonList); |
|||
if (this.editingPropertyIndex !== -1) { |
|||
this.modelerStore.modeling.updateModdleProperties(this.bpmnElement, this.bpmnElementButtonList[this.editingPropertyIndex], { |
|||
name, |
|||
value |
|||
}); |
|||
} else { |
|||
// 新建属性字段 |
|||
const newPropertyObject = this.modelerStore.moddle.create(`flowable:Button`, { name, value }); |
|||
// 新建一个属性字段的保存列表 |
|||
const propertiesObject = this.modelerStore.moddle.create(`flowable:Buttons`, { |
|||
values: this.bpmnElementButtonList.concat([newPropertyObject]) |
|||
}); |
|||
this.updateElementExtensions(propertiesObject); |
|||
} |
|||
this.buttonFormModelVisible = false; |
|||
this.resetAttributesList(); |
|||
}, |
|||
updateElementExtensions(properties) { |
|||
const extensions = this.modelerStore.moddle.create("bpmn:ExtensionElements", { |
|||
values: this.otherExtensionList.concat([properties]) |
|||
}); |
|||
|
|||
this.modelerStore.modeling.updateProperties(this.bpmnElement, { |
|||
extensionElements: extensions |
|||
}); |
|||
} |
|||
} |
|||
}; |
|||
</script> |
|||
@ -0,0 +1,139 @@ |
|||
<template> |
|||
<div class="panel-tab__content"> |
|||
<el-table :data="elementPropertyList" size="mini" max-height="240" border fit> |
|||
<el-table-column label="序号" width="50px" type="index" /> |
|||
<el-table-column label="属性名" prop="name" min-width="100px" show-overflow-tooltip /> |
|||
<el-table-column label="属性值" prop="value" min-width="100px" show-overflow-tooltip /> |
|||
<el-table-column label="操作" width="90px"> |
|||
<template slot-scope="{ row, $index }"> |
|||
<el-button size="mini" type="text" @click="openAttributesForm(row, $index)">编辑</el-button> |
|||
<el-divider direction="vertical" /> |
|||
<el-button size="mini" type="text" style="color: #ff4d4f" @click="removeAttributes(row, $index)">移除</el-button> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
<div class="element-drawer__button"> |
|||
<el-button size="mini" type="primary" icon="el-icon-plus" @click="openAttributesForm(null, -1)">添加属性</el-button> |
|||
</div> |
|||
|
|||
<el-dialog :visible.sync="propertyFormModelVisible" title="属性配置" width="600px" append-to-body destroy-on-close> |
|||
<el-form :model="propertyForm" label-width="80px" size="mini" ref="attributeFormRef" @submit.native.prevent> |
|||
<el-form-item label="属性名:" prop="name"> |
|||
<el-input v-model="propertyForm.name" clearable /> |
|||
</el-form-item> |
|||
<el-form-item label="属性值:" prop="value"> |
|||
<el-input v-model="propertyForm.value" clearable /> |
|||
</el-form-item> |
|||
</el-form> |
|||
<template slot="footer"> |
|||
<el-button size="mini" @click="propertyFormModelVisible = false">取 消</el-button> |
|||
<el-button size="mini" type="primary" @click="saveAttribute">确 定</el-button> |
|||
</template> |
|||
</el-dialog> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import {StrUtil} from "@/utils/StrUtil"; |
|||
|
|||
export default { |
|||
name: "PropertiesPanel", |
|||
props: { |
|||
id: { |
|||
type: String, |
|||
required: true |
|||
}, |
|||
}, |
|||
data() { |
|||
return { |
|||
elementPropertyList: [], |
|||
otherExtensionList: [], |
|||
propertyForm: {}, |
|||
editingPropertyIndex: -1, |
|||
propertyFormModelVisible: false |
|||
}; |
|||
}, |
|||
watch: { |
|||
id: { |
|||
immediate: true, |
|||
handler(val) { |
|||
if (StrUtil.isNotBlank(val)) { |
|||
this.resetAttributesList(); |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
methods: { |
|||
resetAttributesList() { |
|||
this.bpmnElement = this.modelerStore.element; |
|||
this.otherExtensionList = []; // 其他扩展配置 |
|||
this.bpmnElementProperties = |
|||
this.bpmnElement.businessObject?.extensionElements?.values?.filter(ex => { |
|||
if (ex.$type !== `flowable:Properties`) { |
|||
this.otherExtensionList.push(ex); |
|||
} |
|||
return ex.$type === `flowable:Properties`; |
|||
}) ?? []; |
|||
|
|||
// 保存所有的 扩展属性字段 |
|||
this.bpmnElementPropertyList = this.bpmnElementProperties.reduce((pre, current) => pre.concat(current.values), []); |
|||
// 复制 显示 |
|||
this.elementPropertyList = JSON.parse(JSON.stringify(this.bpmnElementPropertyList ?? [])); |
|||
}, |
|||
openAttributesForm(attr, index) { |
|||
this.editingPropertyIndex = index; |
|||
this.propertyForm = index === -1 ? {} : JSON.parse(JSON.stringify(attr)); |
|||
this.propertyFormModelVisible = true; |
|||
this.$nextTick(() => { |
|||
if (this.$refs["attributeFormRef"]) this.$refs["attributeFormRef"].clearValidate(); |
|||
}); |
|||
}, |
|||
removeAttributes(attr, index) { |
|||
this.$confirm("确认移除该属性吗?", "提示", { |
|||
confirmButtonText: "确 认", |
|||
cancelButtonText: "取 消" |
|||
}) |
|||
.then(() => { |
|||
this.elementPropertyList.splice(index, 1); |
|||
this.bpmnElementPropertyList.splice(index, 1); |
|||
// 新建一个属性字段的保存列表 |
|||
const propertiesObject = this.modelerStore.moddle.create(`flowable:Properties`, { |
|||
values: this.bpmnElementPropertyList |
|||
}); |
|||
this.updateElementExtensions(propertiesObject); |
|||
this.resetAttributesList(); |
|||
}) |
|||
.catch(() => console.info("操作取消")); |
|||
}, |
|||
saveAttribute() { |
|||
const { name, value } = this.propertyForm; |
|||
console.log(this.bpmnElementPropertyList); |
|||
if (this.editingPropertyIndex !== -1) { |
|||
this.modelerStore.modeling.updateModdleProperties(this.bpmnElement, this.bpmnElementPropertyList[this.editingPropertyIndex], { |
|||
name, |
|||
value |
|||
}); |
|||
} else { |
|||
// 新建属性字段 |
|||
const newPropertyObject = this.modelerStore.moddle.create(`flowable:Property`, { name, value }); |
|||
// 新建一个属性字段的保存列表 |
|||
const propertiesObject = this.modelerStore.moddle.create(`flowable:Properties`, { |
|||
values: this.bpmnElementPropertyList.concat([newPropertyObject]) |
|||
}); |
|||
this.updateElementExtensions(propertiesObject); |
|||
} |
|||
this.propertyFormModelVisible = false; |
|||
this.resetAttributesList(); |
|||
}, |
|||
updateElementExtensions(properties) { |
|||
const extensions = this.modelerStore.moddle.create("bpmn:ExtensionElements", { |
|||
values: this.otherExtensionList.concat([properties]) |
|||
}); |
|||
|
|||
this.modelerStore.modeling.updateProperties(this.bpmnElement, { |
|||
extensionElements: extensions |
|||
}); |
|||
} |
|||
} |
|||
}; |
|||
</script> |
|||
@ -0,0 +1,87 @@ |
|||
<template> |
|||
<div> |
|||
<el-form :model="bpmnFormData" label-width="80px" :rules="rules" size="small"> |
|||
<el-form-item :label="bpmnFormData.$type === 'bpmn:Process'? '流程标识': '节点ID'" prop="id" @change="updateElementTask('id')"> |
|||
<el-input v-model="bpmnFormData.id"/> |
|||
</el-form-item> |
|||
<el-form-item :label="bpmnFormData.$type === 'bpmn:Process'? '流程名称': '节点名称'" prop="name"> |
|||
<el-input v-model="bpmnFormData.name" @change="updateElementTask('name')"/> |
|||
</el-form-item> |
|||
<!--流程的基础属性--> |
|||
<template v-if="bpmnFormData.$type === 'bpmn:Process'"> |
|||
<el-form-item label="流程分类" prop="processCategory"> |
|||
<el-select v-model="bpmnFormData.processCategory" placeholder="请选择流程分类" @change="updateElementTask('processCategory')"> |
|||
<el-option |
|||
v-for="dict in dict.type.sys_process_category" |
|||
:key="dict.value" |
|||
:label="dict.label" |
|||
:value="dict.value" |
|||
></el-option> |
|||
</el-select> |
|||
</el-form-item> |
|||
</template> |
|||
<el-form-item v-if="bpmnFormData.$type === 'bpmn:SubProcess'" label="状态"> |
|||
<el-switch v-model="bpmnFormData.isExpanded" active-text="展开" inactive-text="折叠" @change="updateElementTask('isExpanded')" /> |
|||
</el-form-item> |
|||
<el-form-item label="节点描述"> |
|||
<el-input :rows="2" type="textarea" v-model="bpmnFormData.documentation" @change="updateElementTask('documentation')"/> |
|||
</el-form-item> |
|||
</el-form> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import {StrUtil} from '@/utils/StrUtil' |
|||
|
|||
export default { |
|||
name: "CommonPanel", |
|||
dicts: ['sys_process_category'], |
|||
/** 组件传值 */ |
|||
props : { |
|||
id: { |
|||
type: String, |
|||
required: true |
|||
}, |
|||
}, |
|||
data() { |
|||
return { |
|||
rules:{ |
|||
id: [ |
|||
{ required: true, message: '节点Id 不能为空', trigger: 'blur' }, |
|||
], |
|||
name: [ |
|||
{ required: true, message: '节点名称不能为空', trigger: 'blur' }, |
|||
], |
|||
}, |
|||
bpmnFormData: {} |
|||
} |
|||
}, |
|||
/** 传值监听 */ |
|||
watch: { |
|||
id: { |
|||
handler(newVal) { |
|||
if (StrUtil.isNotBlank(newVal)) { |
|||
this.resetTaskForm(); |
|||
} |
|||
}, |
|||
immediate: true, // 立即生效 |
|||
}, |
|||
}, |
|||
|
|||
created() { |
|||
|
|||
}, |
|||
methods: { |
|||
resetTaskForm() { |
|||
this.bpmnFormData = JSON.parse(JSON.stringify(this.modelerStore.element.businessObject)); |
|||
}, |
|||
updateElementTask(key) { |
|||
const taskAttr = Object.create(null); |
|||
taskAttr[key] = this.bpmnFormData[key] || null; |
|||
this.modelerStore.modeling.updateProperties(this.modelerStore.element, taskAttr); |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
</script> |
|||
@ -0,0 +1,175 @@ |
|||
<template> |
|||
<div> |
|||
<el-form label-width="100px" size="small" @submit.native.prevent> |
|||
<el-form-item> |
|||
<template slot="label"> |
|||
<span> |
|||
流转类型 |
|||
<el-tooltip placement="top"> |
|||
<template slot="content"> |
|||
<div> |
|||
普通流转路径:流程执行过程中,一个元素被访问后,会沿着其所有出口顺序流继续执行。 |
|||
<br />默认流转路径:只有当没有其他顺序流可以选择时,才会选择默认顺序流作为活动的出口顺序流。流程会忽略默认顺序流上的条件。 |
|||
<br />条件流转路径:是计算其每个出口顺序流上的条件。当条件计算为true时,选择该出口顺序流。如果该方法选择了多条顺序流,则会生成多个执行,流程会以并行方式继续。 |
|||
</div> |
|||
</template> |
|||
<i class="el-icon-question" /> |
|||
</el-tooltip> |
|||
</span> |
|||
</template> |
|||
<el-select v-model="bpmnFormData.type" @change="updateFlowType"> |
|||
<el-option label="普通流转路径" value="normal" /> |
|||
<el-option label="默认流转路径" value="default" /> |
|||
<el-option label="条件流转路径" value="condition" /> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item label="条件格式" v-if="bpmnFormData.type === 'condition'" key="condition"> |
|||
<el-select v-model="bpmnFormData.conditionType"> |
|||
<el-option label="表达式" value="expression" /> |
|||
<el-option label="脚本" value="script" /> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item label="表达式" v-if="bpmnFormData.conditionType && bpmnFormData.conditionType === 'expression'" key="express"> |
|||
<el-input v-model="bpmnFormData.body" clearable @change="updateFlowCondition" /> |
|||
</el-form-item> |
|||
<template v-if="bpmnFormData.conditionType && bpmnFormData.conditionType === 'script'"> |
|||
<el-form-item label="脚本语言" key="language"> |
|||
<el-input v-model="bpmnFormData.language" clearable @change="updateFlowCondition" /> |
|||
</el-form-item> |
|||
<el-form-item label="脚本类型" key="scriptType"> |
|||
<el-select v-model="bpmnFormData.scriptType"> |
|||
<el-option label="内联脚本" value="inlineScript" /> |
|||
<el-option label="外部脚本" value="externalScript" /> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item label="脚本" v-if="bpmnFormData.scriptType === 'inlineScript'" key="body"> |
|||
<el-input v-model="bpmnFormData.body" type="textarea" clearable @change="updateFlowCondition" /> |
|||
</el-form-item> |
|||
<el-form-item label="资源地址" v-if="bpmnFormData.scriptType === 'externalScript'" key="resource"> |
|||
<el-input v-model="bpmnFormData.resource" clearable @change="updateFlowCondition" /> |
|||
</el-form-item> |
|||
</template> |
|||
</el-form> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
|
|||
import {StrUtil} from "@/utils/StrUtil"; |
|||
export default { |
|||
name: "BpmnModel", |
|||
/** 组件传值 */ |
|||
props : { |
|||
id: { |
|||
type: String, |
|||
required: true |
|||
}, |
|||
}, |
|||
data() { |
|||
return { |
|||
bpmnElementSource: {}, |
|||
bpmnElementSourceRef: {}, |
|||
bpmnFormData: {} |
|||
} |
|||
}, |
|||
|
|||
/** 传值监听 */ |
|||
watch: { |
|||
id: { |
|||
handler(newVal) { |
|||
if (StrUtil.isNotBlank(newVal)) { |
|||
this.resetFlowCondition(); |
|||
} |
|||
}, |
|||
immediate: true, // 立即生效 |
|||
}, |
|||
}, |
|||
created() { |
|||
|
|||
}, |
|||
methods: { |
|||
// 方法区 |
|||
resetFlowCondition() { |
|||
this.bpmnFormData = { |
|||
body: null |
|||
}; |
|||
this.bpmnElementSource = this.modelerStore.element.source; |
|||
this.bpmnElementSourceRef = this.modelerStore.element.businessObject.sourceRef; |
|||
if (this.bpmnElementSourceRef && this.bpmnElementSourceRef.default && this.bpmnElementSourceRef.default.id === this.modelerStore.element.id) { |
|||
// 默认 |
|||
this.$set(this.bpmnFormData, "type", "default"); |
|||
} else if (!this.modelerStore.element.businessObject.conditionExpression) { |
|||
// 普通 |
|||
this.$set(this.bpmnFormData, "type", "normal"); |
|||
} else { |
|||
// 带条件 |
|||
const conditionExpression = this.modelerStore.element.businessObject.conditionExpression; |
|||
this.bpmnFormData = {...conditionExpression, type: "condition"}; |
|||
// resource 可直接标识 是否是外部资源脚本 |
|||
if (this.bpmnFormData.resource) { |
|||
this.$set(this.bpmnFormData, "conditionType", "script"); |
|||
this.$set(this.bpmnFormData, "scriptType", "externalScript"); |
|||
return; |
|||
} |
|||
if (conditionExpression.language) { |
|||
this.$set(this.bpmnFormData, "conditionType", "script"); |
|||
this.$set(this.bpmnFormData, "scriptType", "inlineScript"); |
|||
return; |
|||
} |
|||
this.$set(this.bpmnFormData, "conditionType", "expression"); |
|||
} |
|||
}, |
|||
|
|||
updateFlowType(flowType) { |
|||
// 正常条件类 |
|||
if (flowType === "condition") { |
|||
const flowConditionRef = this.modelerStore.moddle.create("bpmn:FormalExpression"); |
|||
this.modelerStore.modeling.updateProperties(this.modelerStore.element, { |
|||
conditionExpression: flowConditionRef |
|||
}); |
|||
return; |
|||
} |
|||
// 默认路径 |
|||
if (flowType === "default") { |
|||
this.modelerStore.modeling.updateProperties(this.modelerStore.element, { |
|||
conditionExpression: null |
|||
}); |
|||
this.modelerStore.modeling.updateProperties(this.bpmnElementSource, { |
|||
default: this.modelerStore.element |
|||
}); |
|||
// 清空条件格式 |
|||
this.bpmnFormData.conditionType = null; |
|||
return; |
|||
} |
|||
// 清空条件格式 |
|||
this.bpmnFormData.conditionType = null; |
|||
// 正常路径,如果来源节点的默认路径是当前连线时,清除父元素的默认路径配置 |
|||
if (this.bpmnElementSourceRef.default && this.bpmnElementSourceRef.default.id === this.modelerStore.element.id) { |
|||
this.modelerStore.modeling.updateProperties(this.bpmnElementSource, { |
|||
default: null |
|||
}); |
|||
} |
|||
this.modelerStore.modeling.updateProperties(this.modelerStore.element, { |
|||
conditionExpression: null |
|||
}); |
|||
}, |
|||
|
|||
updateFlowCondition() { |
|||
let {conditionType, scriptType, body, resource, language} = this.bpmnFormData; |
|||
let condition; |
|||
if (conditionType === "expression") { |
|||
condition = this.modelerStore.moddle.create("bpmn:FormalExpression", {body}); |
|||
} else { |
|||
if (scriptType === "inlineScript") { |
|||
condition = this.modelerStore.moddle.create("bpmn:FormalExpression", {body, language}); |
|||
this.$set(this.bpmnFormData, "resource", ""); |
|||
} else { |
|||
this.$set(this.bpmnFormData, "body", ""); |
|||
condition = this.modelerStore.moddle.create("bpmn:FormalExpression", {resource, language}); |
|||
} |
|||
} |
|||
this.modelerStore.modeling.updateProperties(this.modelerStore.element, {conditionExpression: condition}); |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
@ -0,0 +1,472 @@ |
|||
<template> |
|||
<div class="panel-tab__content"> |
|||
<el-table :data="elementListenersList" size="mini" border> |
|||
<el-table-column label="序号" width="50px" type="index" /> |
|||
<el-table-column label="类型" width="60px" prop="event" /> |
|||
<el-table-column label="监听类型" width="80px" show-overflow-tooltip :formatter="row => listenerTypeObject[row.listenerType]" /> |
|||
<el-table-column label="操作"> |
|||
<template slot-scope="scope"> |
|||
<el-button size="mini" type="primary" @click="openListenerForm(scope.row, scope.$index)">编辑</el-button> |
|||
<el-divider direction="vertical" /> |
|||
<el-button size="mini" type="danger" @click="removeListener(scope.row, scope.$index)">移除</el-button> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
<div class="element-drawer__button_save"> |
|||
<el-button type="primary" icon="el-icon-plus" size="small" @click="listenerSystemVisible = true">内置监听器</el-button> |
|||
<el-button type="primary" icon="el-icon-plus" size="small" @click="openListenerForm(null)" >自定义监听器</el-button> |
|||
</div> |
|||
|
|||
<!-- 监听器 编辑/创建 部分 --> |
|||
<el-drawer :visible.sync="listenerFormModelVisible" title="执行监听器" size="480px" append-to-body destroy-on-close> |
|||
<el-form :model="listenerForm" size="small" label-width="96px" ref="listenerFormRef" @submit.native.prevent> |
|||
<el-form-item label="事件类型" prop="event" :rules="{ required: true, trigger: ['blur', 'change'] }"> |
|||
<el-select v-model="listenerForm.event"> |
|||
<el-option label="start" value="start" /> |
|||
<el-option label="end" value="end" /> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item label="监听器类型" prop="listenerType" :rules="{ required: true, trigger: ['blur', 'change'] }"> |
|||
<el-select v-model="listenerForm.listenerType"> |
|||
<el-option v-for="i in Object.keys(listenerTypeObject)" :key="i" :label="listenerTypeObject[i]" :value="i" /> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item |
|||
v-if="listenerForm.listenerType === 'classListener'" |
|||
label="Java类" |
|||
prop="class" |
|||
key="listener-class" |
|||
:rules="{ required: true, trigger: ['blur', 'change'] }" |
|||
> |
|||
<el-input v-model="listenerForm.class" clearable /> |
|||
</el-form-item> |
|||
<el-form-item |
|||
v-if="listenerForm.listenerType === 'expressionListener'" |
|||
label="表达式" |
|||
prop="expression" |
|||
key="listener-expression" |
|||
:rules="{ required: true, trigger: ['blur', 'change'] }" |
|||
> |
|||
<el-input v-model="listenerForm.expression" clearable /> |
|||
</el-form-item> |
|||
<el-form-item |
|||
v-if="listenerForm.listenerType === 'delegateExpressionListener'" |
|||
label="代理表达式" |
|||
prop="delegateExpression" |
|||
key="listener-delegate" |
|||
:rules="{ required: true, trigger: ['blur', 'change'] }" |
|||
> |
|||
<el-input v-model="listenerForm.delegateExpression" clearable /> |
|||
</el-form-item> |
|||
<template v-if="listenerForm.listenerType === 'scriptListener'"> |
|||
<el-form-item |
|||
label="脚本格式" |
|||
prop="scriptFormat" |
|||
key="listener-script-format" |
|||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写脚本格式' }" |
|||
> |
|||
<el-input v-model="listenerForm.scriptFormat" clearable /> |
|||
</el-form-item> |
|||
<el-form-item |
|||
label="脚本类型" |
|||
prop="scriptType" |
|||
key="listener-script-type" |
|||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请选择脚本类型' }" |
|||
> |
|||
<el-select v-model="listenerForm.scriptType"> |
|||
<el-option label="内联脚本" value="inlineScript" /> |
|||
<el-option label="外部脚本" value="externalScript" /> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item |
|||
v-if="listenerForm.scriptType === 'inlineScript'" |
|||
label="脚本内容" |
|||
prop="value" |
|||
key="listener-script" |
|||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写脚本内容' }" |
|||
> |
|||
<el-input v-model="this.listenerForm" clearable /> |
|||
</el-form-item> |
|||
<el-form-item |
|||
v-if="listenerForm.scriptType === 'externalScript'" |
|||
label="资源地址" |
|||
prop="resource" |
|||
key="listener-resource" |
|||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写资源地址' }" |
|||
> |
|||
<el-input v-model="listenerForm.resource" clearable /> |
|||
</el-form-item> |
|||
</template> |
|||
</el-form> |
|||
<el-divider /> |
|||
<p class="listener-filed__title"> |
|||
<span><el-icon><BellFilled /></el-icon>注入字段:</span> |
|||
<el-button type="primary" size="mini" @click="openListenerFieldForm(null)">添加字段</el-button> |
|||
</p> |
|||
<el-table :data="fieldsListOfListener" size="mini" max-height="240" border fit style="flex: none"> |
|||
<el-table-column label="序号" width="50px" type="index" /> |
|||
<el-table-column label="字段名称" width="80px" prop="name" /> |
|||
<el-table-column label="字段类型" width="80px" show-overflow-tooltip :formatter="row => fieldTypeObject[row.fieldType]" /> |
|||
<el-table-column label="值内容" width="80px" show-overflow-tooltip :formatter="row => row.string || row.expression" /> |
|||
<el-table-column label="操作"> |
|||
<template slot-scope="scope"> |
|||
<el-button size="mini" type="primary" @click="openListenerFieldForm(scope.row, scope.$index)">编辑</el-button> |
|||
<el-divider direction="vertical" /> |
|||
<el-button size="mini" type="danger" @click="removeListenerField(scope.row, scope.$index)">移除</el-button> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
|
|||
<div class="element-drawer__button"> |
|||
<el-button size="small" @click="listenerFormModelVisible = false">取 消</el-button> |
|||
<el-button size="small" type="primary" @click="saveListenerConfig">保 存</el-button> |
|||
</div> |
|||
</el-drawer> |
|||
|
|||
<!-- 注入西段 编辑/创建 部分 --> |
|||
<el-dialog title="字段配置" :visible.sync="listenerFieldFormModelVisible" width="600px" append-to-body destroy-on-close> |
|||
<el-form :model="listenerFieldForm" label-width="96px" ref="listenerFieldFormRef" style="height: 136px" @submit.native.prevent> |
|||
<el-form-item label="字段名称:" prop="name" :rules="{ required: true, trigger: ['blur', 'change'] }"> |
|||
<el-input v-model="listenerFieldForm.name" clearable /> |
|||
</el-form-item> |
|||
<el-form-item label="字段类型:" prop="fieldType" :rules="{ required: true, trigger: ['blur', 'change'] }"> |
|||
<el-select v-model="listenerFieldForm.fieldType"> |
|||
<el-option v-for="i in Object.keys(fieldTypeObject)" :key="i" :label="fieldTypeObject[i]" :value="i" /> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item |
|||
v-if="listenerFieldForm.fieldType === 'string'" |
|||
label="字段值:" |
|||
prop="string" |
|||
key="field-string" |
|||
:rules="{ required: true, trigger: ['blur', 'change'] }" |
|||
> |
|||
<el-input v-model="listenerFieldForm.string" clearable /> |
|||
</el-form-item> |
|||
<el-form-item |
|||
v-if="listenerFieldForm.fieldType === 'expression'" |
|||
label="表达式:" |
|||
prop="expression" |
|||
key="field-expression" |
|||
:rules="{ required: true, trigger: ['blur', 'change'] }" |
|||
> |
|||
<el-input v-model="listenerFieldForm.expression" clearable /> |
|||
</el-form-item> |
|||
</el-form> |
|||
<div slot="footer" class="dialog-footer"> |
|||
<el-button size="small" @click="listenerFieldFormModelVisible= false">取 消</el-button> |
|||
<el-button size="small" type="primary" @click="saveListenerFiled">确 定</el-button> |
|||
</div> |
|||
</el-dialog> |
|||
|
|||
|
|||
<!-- 内置监听器 --> |
|||
<el-drawer :visible.sync="listenerSystemVisible" title="执行监听器" size="580px" append-to-body destroy-on-close> |
|||
<el-table v-loading="loading" :data="listenerList" @selection-change="handleSelectionChange"> |
|||
<el-table-column type="selection" width="55" align="center" /> |
|||
<el-table-column label="名称" align="center" prop="name" /> |
|||
<el-table-column label="类型" align="center" prop="eventType"/> |
|||
<el-table-column label="监听类型" align="center" prop="valueType"> |
|||
<template slot-scope="scope"> |
|||
<dict-tag :options="dict.type.sys_listener_value_type" :value="scope.row.valueType"/> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column label="执行内容" align="center" prop="value" :show-overflow-tooltip="true"/> |
|||
</el-table> |
|||
|
|||
<pagination |
|||
v-show="total>0" |
|||
:total="total" |
|||
layout="prev, pager, next" |
|||
:page.sync="queryParams.pageNum" |
|||
:limit.sync="queryParams.pageSize" |
|||
@pagination="getList" |
|||
/> |
|||
|
|||
<div class="element-drawer__button"> |
|||
<el-button size="small" @click="listenerSystemVisible = false">取 消</el-button> |
|||
<el-button size="small" type="primary" :disabled="listenerSystemChecked" @click="saveSystemListener">保 存</el-button> |
|||
</div> |
|||
</el-drawer> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { listListener } from "@/api/flowable/listener"; |
|||
import { |
|||
changeListenerObject, |
|||
createListenerObject, |
|||
createSystemListenerObject, |
|||
updateElementExtensions |
|||
} from "../common/bpmnUtils"; |
|||
|
|||
import {StrUtil} from "@/utils/StrUtil"; |
|||
|
|||
export default { |
|||
name: "ExecutionListener", |
|||
// 内置监听器相关信息 |
|||
dicts: ['sys_listener_value_type', 'sys_listener_event_type'], |
|||
/** 组件传值 */ |
|||
props : { |
|||
id: { |
|||
type: String, |
|||
required: true |
|||
}, |
|||
}, |
|||
data() { |
|||
return { |
|||
elementListenersList: [], // 监听器列表 |
|||
listenerForm: {},// 监听器详情表单 |
|||
listenerFormModelVisible: false, // 监听器 编辑 侧边栏显示状态 |
|||
fieldsListOfListener: [], |
|||
bpmnElementListeners: [], |
|||
otherExtensionList: [], |
|||
listenerFieldForm: {}, // 监听器 注入字段 详情表单 |
|||
listenerFieldFormModelVisible: false, // 监听器 注入字段表单弹窗 显示状态 |
|||
editingListenerIndex: -1, // 监听器所在下标,-1 为新增 |
|||
editingListenerFieldIndex: -1, // 字段所在下标,-1 为新增 |
|||
|
|||
listenerList: [], |
|||
checkedListenerData: [], |
|||
listenerSystemVisible: false, |
|||
listenerSystemChecked: true, |
|||
loading: true, |
|||
total: 0, |
|||
listenerTypeObject: { |
|||
classListener: "Java 类", |
|||
expressionListener: "表达式", |
|||
delegateExpressionListener: "代理表达式", |
|||
scriptListener: "脚本" |
|||
}, |
|||
eventType: { |
|||
create: "创建", |
|||
assignment: "指派", |
|||
complete: "完成", |
|||
delete: "删除", |
|||
update: "更新", |
|||
timeout: "超时" |
|||
}, |
|||
fieldTypeObject: { |
|||
string: "字符串", |
|||
expression: "表达式" |
|||
}, |
|||
queryParams: { |
|||
pageNum: 1, |
|||
pageSize: 10, |
|||
type: 2, |
|||
}, |
|||
} |
|||
}, |
|||
|
|||
/** 传值监听 */ |
|||
watch: { |
|||
id: { |
|||
handler(newVal) { |
|||
if (StrUtil.isNotBlank(newVal)) { |
|||
this.resetListenersList(); |
|||
} |
|||
}, |
|||
immediate: true, // 立即生效 |
|||
}, |
|||
}, |
|||
created() { |
|||
this.getList(); |
|||
|
|||
}, |
|||
methods: { |
|||
resetListenersList() { |
|||
this.bpmnElementListeners = |
|||
this.modelerStore.element.businessObject?.extensionElements?.values?.filter(ex => ex.$type === `flowable:ExecutionListener`) ?? []; |
|||
this.elementListenersList = this.bpmnElementListeners.map(listener => this.initListenerType(listener)); |
|||
this.$emit('getExecutionListenerCount', this.elementListenersList.length) |
|||
}, |
|||
|
|||
// 打开 监听器详情 侧边栏 |
|||
openListenerForm(listener, index) { |
|||
if (listener) { |
|||
this.listenerForm = this.initListenerForm(listener); |
|||
this.editingListenerIndex = index; |
|||
} else { |
|||
this.listenerForm = {}; |
|||
this.editingListenerIndex = -1; // 标记为新增 |
|||
} |
|||
if (listener && listener.fields) { |
|||
this.fieldsListOfListener = listener.fields.map(field => ({ |
|||
...field, |
|||
fieldType: field.string ? "string" : "expression" |
|||
})); |
|||
} else { |
|||
this.fieldsListOfListener = []; |
|||
this.$set(this.listenerForm, "fields", []); |
|||
} |
|||
// 打开侧边栏并清楚验证状态 |
|||
this.listenerFormModelVisible = true; |
|||
this.$nextTick(() => { |
|||
if (this.$refs["listenerFormRef"]) this.$refs["listenerFormRef"].clearValidate(); |
|||
}); |
|||
}, |
|||
|
|||
// 打开监听器字段编辑弹窗 |
|||
openListenerFieldForm(field, index) { |
|||
this.listenerFieldForm = field ? JSON.parse(JSON.stringify(field)) : {}; |
|||
this.editingListenerFieldIndex = field ? index : -1; |
|||
this.listenerFieldFormModelVisible = true; |
|||
this.$nextTick(() => { |
|||
if (this.$refs["listenerFieldFormRef"]) this.$refs["listenerFieldFormRef"].clearValidate(); |
|||
}); |
|||
}, |
|||
|
|||
// 保存监听器注入字段 |
|||
async saveListenerFiled() { |
|||
let validateStatus = await this.$refs["listenerFieldFormRef"].validate(); |
|||
if (!validateStatus) return; // 验证不通过直接返回 |
|||
if (this.editingListenerFieldIndex === -1) { |
|||
this.fieldsListOfListener.push(this.listenerFieldForm); |
|||
this.listenerForm.fields.push(this.listenerFieldForm); |
|||
} else { |
|||
this.fieldsListOfListener.splice(this.editingListenerFieldIndex, 1, this.listenerFieldForm); |
|||
this.listenerForm.fields.splice(this.editingListenerFieldIndex, 1, this.listenerFieldForm); |
|||
} |
|||
this.listenerFieldFormModelVisible = false; |
|||
this.$nextTick(() => (this.listenerFieldForm = {})); |
|||
}, |
|||
|
|||
// 移除监听器字段 |
|||
removeListenerField(field, index) { |
|||
this.$confirm("确认移除该字段吗?", "提示", { |
|||
confirmButtonText: "确 认", |
|||
cancelButtonText: "取 消" |
|||
}).then(() => { |
|||
this.fieldsListOfListener.splice(index, 1); |
|||
this.listenerForm.fields.splice(index, 1); |
|||
}).catch(() => console.info("操作取消")); |
|||
}, |
|||
|
|||
// 移除监听器 |
|||
removeListener(listener, index) { |
|||
this.$confirm("确认移除该监听器吗?", "提示", { |
|||
confirmButtonText: "确 认", |
|||
cancelButtonText: "取 消" |
|||
}).then(() => { |
|||
this.bpmnElementListeners.splice(index, 1); |
|||
this.elementListenersList.splice(index, 1); |
|||
updateElementExtensions(this.modelerStore.moddle, this.modelerStore.modeling, this.modelerStore.element, this.otherExtensionList.concat(this.bpmnElementListeners)); |
|||
this.$emit('getExecutionListenerCount', this.elementListenersList.length) |
|||
}).catch((r) => console.info(r, "操作取消")); |
|||
}, |
|||
|
|||
// 保存监听器配置 |
|||
async saveListenerConfig() { |
|||
let validateStatus = await this.$refs["listenerFormRef"].validate(); |
|||
if (!validateStatus) return; // 验证不通过直接返回 |
|||
const listenerObject = createListenerObject(this.modelerStore.moddle, this.listenerForm, false, "flowable"); |
|||
if (this.editingListenerIndex === -1) { |
|||
this.bpmnElementListeners.push(listenerObject); |
|||
this.elementListenersList.push(this.listenerForm); |
|||
} else { |
|||
this.bpmnElementListeners.splice(this.editingListenerIndex, 1, listenerObject); |
|||
this.elementListenersList.splice(this.editingListenerIndex, 1, this.listenerForm); |
|||
} |
|||
// 保存其他配置 |
|||
this.otherExtensionList = this.modelerStore.element.businessObject?.extensionElements?.values?.filter(ex => ex.$type !== `flowable:ExecutionListener`) ?? []; |
|||
updateElementExtensions(this.modelerStore.moddle, this.modelerStore.modeling, this.modelerStore.element, this.otherExtensionList.concat(this.bpmnElementListeners)); |
|||
this.$emit('getExecutionListenerCount', this.elementListenersList.length) |
|||
// 4. 隐藏侧边栏 |
|||
this.listenerFormModelVisible = false; |
|||
this.listenerForm = {}; |
|||
}, |
|||
|
|||
initListenerType(listener) { |
|||
let listenerType; |
|||
if (listener.class) listenerType = "classListener"; |
|||
if (listener.expression) listenerType = "expressionListener"; |
|||
if (listener.delegateExpression) listenerType = "delegateExpressionListener"; |
|||
if (listener.script) listenerType = "scriptListener"; |
|||
return { |
|||
...JSON.parse(JSON.stringify(listener)), |
|||
...(listener.script ?? {}), |
|||
listenerType: listenerType |
|||
}; |
|||
}, |
|||
|
|||
// 初始化表单数据 |
|||
initListenerForm(listener) { |
|||
let self = { |
|||
...listener |
|||
}; |
|||
if (listener.script) { |
|||
self = { |
|||
...listener, |
|||
...listener.script, |
|||
scriptType: listener.script.resource ? "externalScript" : "inlineScript" |
|||
}; |
|||
} |
|||
if (listener.event === "timeout" && listener.eventDefinitions) { |
|||
if (listener.eventDefinitions.length) { |
|||
let k = ""; |
|||
for (let key in listener.eventDefinitions[0]) { |
|||
console.log(listener.eventDefinitions, key); |
|||
if (key.indexOf("time") !== -1) { |
|||
k = key; |
|||
self.eventDefinitionType = key.replace("time", "").toLowerCase(); |
|||
} |
|||
} |
|||
console.log(k); |
|||
self.eventTimeDefinitions = listener.eventDefinitions[0][k].body; |
|||
} |
|||
} |
|||
return self; |
|||
}, |
|||
|
|||
|
|||
/** 查询流程达式列表 */ |
|||
getList() { |
|||
this.loading = true; |
|||
listListener(this.queryParams).then(response => { |
|||
this.listenerList = response.rows; |
|||
this.total = response.total; |
|||
this.loading = false; |
|||
}); |
|||
}, |
|||
|
|||
// 多选框选中数据 |
|||
handleSelectionChange(selection) { |
|||
// ids.value = selection.map(item => item.id); |
|||
// TODO 应该使用 push? |
|||
this.checkedListenerData = selection; |
|||
this.listenerSystemChecked = selection.length !== 1; |
|||
}, |
|||
|
|||
// 保存内置监听器 |
|||
saveSystemListener() { |
|||
if (this.checkedListenerData.length > 0) { |
|||
this.checkedListenerData.forEach(value => { |
|||
// 保存其他配置 |
|||
const listenerObject = createSystemListenerObject(this.modelerStore.moddle, value, false, "flowable"); |
|||
this.bpmnElementListeners.push(listenerObject); |
|||
this.elementListenersList.push(changeListenerObject(value)); |
|||
this.otherExtensionList = this.modelerStore.element.businessObject?.extensionElements?.values?.filter(ex => ex.$type !== `flowable:TaskListener`) ?? []; |
|||
updateElementExtensions(this.modelerStore.moddle, this.modelerStore.modeling, this.modelerStore.element, this.otherExtensionList.concat(this.bpmnElementListeners)); |
|||
}) |
|||
// 回传显示数量 |
|||
this.$emit('getExecutionListenerCount', this.elementListenersList.length) |
|||
} |
|||
this.checkedListenerData = []; |
|||
this.listenerSystemChecked = true; |
|||
// 隐藏侧边栏 |
|||
this.listenerSystemVisible = false; |
|||
} |
|||
} |
|||
} |
|||
|
|||
</script> |
|||
|
|||
<style lang="scss"> |
|||
@import '../style/process-panel'; |
|||
.flow-containers .el-badge__content.is-fixed { |
|||
top: 18px; |
|||
} |
|||
.dialog-footer button:first-child { |
|||
margin-right: 10px; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,82 @@ |
|||
<template> |
|||
<div> |
|||
<el-form label-width="80px" size="small" @submit.native.prevent> |
|||
<el-form-item label="流程表单"> |
|||
<el-select v-model="bpmnFormData.formKey" clearable class="m-2" placeholder="挂载节点表单" @change="updateElementFormKey"> |
|||
<el-option |
|||
v-for="item in formList" |
|||
:key="item.value" |
|||
:label="item.formName" |
|||
:value="item.formId" |
|||
/> |
|||
</el-select> |
|||
</el-form-item> |
|||
</el-form> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
|
|||
import { listAllForm } from '@/api/flowable/form' |
|||
import {StrUtil} from "@/utils/StrUtil"; |
|||
export default { |
|||
name: "FormPanel", |
|||
/** 组件传值 */ |
|||
props : { |
|||
id: { |
|||
type: String, |
|||
required: true |
|||
}, |
|||
}, |
|||
data() { |
|||
return { |
|||
formList: [], // 表单数据 |
|||
bpmnFormData: {} |
|||
} |
|||
}, |
|||
|
|||
/** 传值监听 */ |
|||
watch: { |
|||
id: { |
|||
handler(newVal) { |
|||
if (StrUtil.isNotBlank(newVal)) { |
|||
// 加载表单列表 |
|||
this.getListForm(); |
|||
this.resetFlowForm(); |
|||
} |
|||
}, |
|||
immediate: true, // 立即生效 |
|||
}, |
|||
}, |
|||
created() { |
|||
|
|||
}, |
|||
methods: { |
|||
|
|||
// 方法区 |
|||
resetFlowForm() { |
|||
this.bpmnFormData.formKey = this.modelerStore.element.businessObject.formKey; |
|||
}, |
|||
|
|||
updateElementFormKey(val) { |
|||
if (StrUtil.isBlank(val)) { |
|||
delete this.modelerStore.element.businessObject[`formKey`] |
|||
} else { |
|||
this.modelerStore.modeling.updateProperties(this.modelerStore.element, {'formKey': val}); |
|||
} |
|||
}, |
|||
|
|||
// 获取表单信息 |
|||
getListForm() { |
|||
listAllForm().then(res => { |
|||
res.data.forEach(item => { |
|||
item.formId = item.formId.toString(); |
|||
}) |
|||
this.formList = res.data; |
|||
}) |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
</script> |
|||
@ -0,0 +1,236 @@ |
|||
<template> |
|||
<div class="panel-tab__content"> |
|||
<el-form label-width="70px" @submit.native.prevent size="small"> |
|||
<el-form-item label="参数说明"> |
|||
<el-button size="small" type="primary" @click="dialogVisible = true">查看</el-button> |
|||
</el-form-item> |
|||
<el-form-item label="回路特性"> |
|||
<el-select v-model="loopCharacteristics" @change="changeLoopCharacteristicsType"> |
|||
<!--bpmn:MultiInstanceLoopCharacteristics--> |
|||
<el-option label="并行多重事件" value="ParallelMultiInstance" /> |
|||
<el-option label="时序多重事件" value="SequentialMultiInstance" /> |
|||
<!--bpmn:StandardLoopCharacteristics--> |
|||
<el-option label="循环事件" value="StandardLoop" /> |
|||
<el-option label="无" value="Null" /> |
|||
</el-select> |
|||
</el-form-item> |
|||
<template v-if="loopCharacteristics === 'ParallelMultiInstance' || loopCharacteristics === 'SequentialMultiInstance'"> |
|||
<el-form-item label="循环基数" key="loopCardinality"> |
|||
<el-input v-model="loopInstanceForm.loopCardinality" clearable @change="updateLoopCardinality" /> |
|||
</el-form-item> |
|||
<el-form-item label="集合" key="collection"> |
|||
<el-input v-model="loopInstanceForm.collection" clearable @change="updateLoopBase" /> |
|||
</el-form-item> |
|||
<el-form-item label="元素变量" key="elementVariable"> |
|||
<el-input v-model="loopInstanceForm.elementVariable" clearable @change="updateLoopBase" /> |
|||
</el-form-item> |
|||
<el-form-item label="完成条件" key="completionCondition"> |
|||
<el-input v-model="loopInstanceForm.completionCondition" clearable @change="updateLoopCondition" /> |
|||
</el-form-item> |
|||
<el-form-item label="异步状态" key="async"> |
|||
<el-checkbox v-model="loopInstanceForm.asyncBefore" label="异步前" @change="updateLoopAsync('asyncBefore')" /> |
|||
<el-checkbox v-model="loopInstanceForm.asyncAfter" label="异步后" @change="updateLoopAsync('asyncAfter')" /> |
|||
<el-checkbox |
|||
v-model="loopInstanceForm.exclusive" |
|||
v-if="loopInstanceForm.asyncAfter || loopInstanceForm.asyncBefore" |
|||
label="排除" |
|||
@change="updateLoopAsync('exclusive')" |
|||
/> |
|||
</el-form-item> |
|||
<el-form-item label="重试周期" prop="timeCycle" v-if="loopInstanceForm.asyncAfter || loopInstanceForm.asyncBefore" key="timeCycle"> |
|||
<el-input v-model="loopInstanceForm.timeCycle" clearable @change="updateLoopTimeCycle" /> |
|||
</el-form-item> |
|||
</template> |
|||
</el-form> |
|||
|
|||
<!-- 参数说明 --> |
|||
<el-dialog title="多实例参数" :visible.sync="dialogVisible" width="680px" @closed="$emit('close')"> |
|||
<el-descriptions :column="1" border> |
|||
<el-descriptions-item label="使用说明">按照BPMN2.0规范的要求,用于为每个实例创建执行的父执行,会提供下列变量:</el-descriptions-item> |
|||
<el-descriptions-item label="collection(集合变量)">传入List参数, 一般为用户ID集合</el-descriptions-item> |
|||
<el-descriptions-item label="elementVariable(元素变量)">List中单个参数的名称</el-descriptions-item> |
|||
<el-descriptions-item label="loopCardinality(基数)">List循环次数</el-descriptions-item> |
|||
<el-descriptions-item label="isSequential(串并行)">Parallel: 并行多实例,Sequential: 串行多实例</el-descriptions-item> |
|||
<el-descriptions-item label="completionCondition(完成条件)">任务出口条件</el-descriptions-item> |
|||
<el-descriptions-item label="nrOfInstances(实例总数)">实例总数</el-descriptions-item> |
|||
<el-descriptions-item label="nrOfActiveInstances(未完成数)">当前活动的(即未完成的),实例数量。对于顺序多实例,这个值总为1</el-descriptions-item> |
|||
<el-descriptions-item label="nrOfCompletedInstances(已完成数)">已完成的实例数量</el-descriptions-item> |
|||
<el-descriptions-item label="loopCounter">给定实例在for-each循环中的index</el-descriptions-item> |
|||
</el-descriptions> |
|||
</el-dialog> |
|||
</div> |
|||
</template> |
|||
<script> |
|||
import {StrUtil} from '@/utils/StrUtil' |
|||
|
|||
|
|||
export default { |
|||
name: "MultiInstance", |
|||
/** 组件传值 */ |
|||
props: { |
|||
id: { |
|||
type: String, |
|||
required: true |
|||
}, |
|||
}, |
|||
data() { |
|||
return { |
|||
dialogVisible: false, |
|||
loopCharacteristics: "", |
|||
loopInstanceForm: {}, |
|||
multiLoopInstance: {}, |
|||
defaultLoopInstanceForm: { |
|||
completionCondition: "", |
|||
loopCardinality: "", |
|||
extensionElements: [], |
|||
asyncAfter: false, |
|||
asyncBefore: false, |
|||
exclusive: false |
|||
}, |
|||
} |
|||
}, |
|||
|
|||
/** 传值监听 */ |
|||
watch: { |
|||
id: { |
|||
handler(newVal) { |
|||
if (StrUtil.isNotBlank(newVal)) { |
|||
this.getElementLoop(this.modelerStore.element.businessObject); } |
|||
}, |
|||
immediate: true, // 立即生效 |
|||
}, |
|||
}, |
|||
created() { |
|||
|
|||
}, |
|||
methods: { |
|||
// 方法区 |
|||
getElementLoop(businessObject) { |
|||
if (!businessObject.loopCharacteristics) { |
|||
this.loopCharacteristics = "Null"; |
|||
this.loopInstanceForm = {}; |
|||
return; |
|||
} |
|||
if (businessObject.loopCharacteristics.$type === "bpmn:StandardLoopCharacteristics") { |
|||
this.loopCharacteristics = "StandardLoop"; |
|||
this.loopInstanceForm = {}; |
|||
return; |
|||
} |
|||
if (businessObject.loopCharacteristics.isSequential) { |
|||
this.loopCharacteristics = "SequentialMultiInstance"; |
|||
} else { |
|||
this.loopCharacteristics = "ParallelMultiInstance"; |
|||
} |
|||
// 合并配置 |
|||
this.loopInstanceForm = { |
|||
...this.defaultLoopInstanceForm, |
|||
...businessObject.loopCharacteristics, |
|||
completionCondition: businessObject.loopCharacteristics?.completionCondition?.body ?? "", |
|||
loopCardinality: businessObject.loopCharacteristics?.loopCardinality?.body ?? "" |
|||
}; |
|||
// 保留当前元素 businessObject 上的 loopCharacteristics 实例 |
|||
this.multiLoopInstance = this.modelerStore.element.businessObject.loopCharacteristics; |
|||
// 更新表单 |
|||
if ( |
|||
businessObject.loopCharacteristics.extensionElements && |
|||
businessObject.loopCharacteristics.extensionElements.values && |
|||
businessObject.loopCharacteristics.extensionElements.values.length |
|||
) { |
|||
this.$set(this.loopInstanceForm, "timeCycle", businessObject.loopCharacteristics.extensionElements.values[0].body); |
|||
} |
|||
}, |
|||
|
|||
changeLoopCharacteristicsType(type) { |
|||
// 切换类型取消原表单配置 |
|||
this.loopInstanceForm = {...this.defaultLoopInstanceForm}; |
|||
// 取消多实例配置 |
|||
if (type === "Null") { |
|||
this.modelerStore.modeling.updateProperties(this.modelerStore.element, {loopCharacteristics: null}); |
|||
return; |
|||
} |
|||
// 配置循环 |
|||
if (type === "StandardLoop") { |
|||
const loopCharacteristicsObject = this.modelerStore.moddle.create("bpmn:StandardLoopCharacteristics"); |
|||
this.modelerStore.modeling.updateProperties(this.modelerStore.element, { |
|||
loopCharacteristics: loopCharacteristicsObject |
|||
}); |
|||
this.multiLoopInstance = null; |
|||
return; |
|||
} |
|||
// 时序 |
|||
if (type === "SequentialMultiInstance") { |
|||
this.multiLoopInstance = this.modelerStore.moddle.create("bpmn:MultiInstanceLoopCharacteristics", { |
|||
isSequential: true |
|||
}); |
|||
} else { |
|||
this.multiLoopInstance = this.modelerStore.moddle.create("bpmn:MultiInstanceLoopCharacteristics"); |
|||
} |
|||
this.modelerStore.modeling.updateProperties(this.modelerStore.element, { |
|||
loopCharacteristics: this.multiLoopInstance |
|||
}); |
|||
}, |
|||
|
|||
// 循环基数 |
|||
updateLoopCardinality(cardinality) { |
|||
let loopCardinality = null; |
|||
if (cardinality && cardinality.length) { |
|||
loopCardinality = this.modelerStore.moddle.create("bpmn:FormalExpression", {body: cardinality}); |
|||
} |
|||
this.modelerStore.modeling.updateModdleProperties(this.modelerStore.element, this.multiLoopInstance, { |
|||
loopCardinality |
|||
}); |
|||
}, |
|||
|
|||
// 完成条件 |
|||
updateLoopCondition(condition) { |
|||
let completionCondition = null; |
|||
if (condition && condition.length) { |
|||
completionCondition = this.modelerStore.moddle.create("bpmn:FormalExpression", {body: condition}); |
|||
} |
|||
this.modelerStore.modeling.updateModdleProperties(this.modelerStore.element, this.multiLoopInstance, { |
|||
completionCondition |
|||
}); |
|||
}, |
|||
|
|||
// 重试周期 |
|||
updateLoopTimeCycle(timeCycle) { |
|||
const extensionElements = this.modelerStore.moddle.create("bpmn:ExtensionElements", { |
|||
values: [ |
|||
this.modelerStore.moddle.create(`flowable:FailedJobRetryTimeCycle`, { |
|||
body: timeCycle |
|||
}) |
|||
] |
|||
}); |
|||
this.modelerStore.modeling.updateModdleProperties(this.modelerStore.element, this.multiLoopInstance, { |
|||
extensionElements |
|||
}); |
|||
}, |
|||
|
|||
// 直接更新的基础信息 |
|||
updateLoopBase() { |
|||
this.modelerStore.modeling.updateModdleProperties(this.modelerStore.element, this.multiLoopInstance, { |
|||
collection: this.loopInstanceForm.collection || null, |
|||
elementVariable: this.loopInstanceForm.elementVariable || null |
|||
}); |
|||
}, |
|||
|
|||
// 各异步状态 |
|||
updateLoopAsync(key) { |
|||
const {asyncBefore, asyncAfter} = this.loopInstanceForm; |
|||
let asyncAttr = Object.create(null); |
|||
if (!asyncBefore && !asyncAfter) { |
|||
this.$set(this.loopInstanceForm, "exclusive", false); |
|||
asyncAttr = {asyncBefore: false, asyncAfter: false, exclusive: false, extensionElements: null}; |
|||
} else { |
|||
asyncAttr[key] = this.loopInstanceForm[key]; |
|||
} |
|||
this.modelerStore.modeling.updateModdleProperties(this.modelerStore.element, this.multiLoopInstance, asyncAttr); |
|||
} |
|||
} |
|||
} |
|||
|
|||
</script> |
|||
<style lang="scss"> |
|||
@import '../style/process-panel'; |
|||
</style> |
|||
|
|||
@ -0,0 +1,65 @@ |
|||
<template> |
|||
<div> |
|||
<el-form label-width="80px" size="small" @submit.native.prevent> |
|||
<el-form-item label="跳过表达式"> |
|||
<el-input v-model="bpmnFormData.skipExpression" @change="updateElementTask('skipExpression')"/> |
|||
</el-form-item> |
|||
<el-form-item label="是否为补偿"> |
|||
<el-input v-model="bpmnFormData.isForCompensation" @change="updateElementTask('isForCompensation')"/> |
|||
</el-form-item> |
|||
<el-form-item label="服务任务可触发"> |
|||
<el-input v-model="bpmnFormData.triggerable" @change="updateElementTask('triggerable')"/> |
|||
</el-form-item> |
|||
</el-form> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
|
|||
import {StrUtil} from "@/utils/StrUtil"; |
|||
export default { |
|||
name: "OtherPanel", |
|||
/** 组件传值 */ |
|||
props : { |
|||
id: { |
|||
type: String, |
|||
required: true |
|||
}, |
|||
}, |
|||
data() { |
|||
return { |
|||
bpmnFormData: {} |
|||
} |
|||
}, |
|||
|
|||
/** 传值监听 */ |
|||
watch: { |
|||
id: { |
|||
handler(newVal) { |
|||
if (StrUtil.isNotBlank(newVal)) { |
|||
this.resetTaskForm(); |
|||
} |
|||
}, |
|||
immediate: true, // 立即生效 |
|||
}, |
|||
}, |
|||
created() { |
|||
|
|||
}, |
|||
methods: { |
|||
// 方法区 |
|||
resetFlowForm() { |
|||
this.bpmnFormData = JSON.parse(JSON.stringify(this.modelerStore.element.businessObject)); |
|||
}, |
|||
|
|||
updateElementTask(key) { |
|||
const taskAttr = Object.create(null); |
|||
taskAttr[key] = this.bpmnFormData[key] || null; |
|||
this.modelerStore.modeling.updateProperties(this.modelerStore.element, taskAttr); |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
</script> |
|||
@ -0,0 +1,529 @@ |
|||
<template> |
|||
<div class="panel-tab__content"> |
|||
<el-table :data="elementListenersList" border size="mini"> |
|||
<el-table-column label="序号" width="50px" type="index" /> |
|||
<el-table-column label="类型" width="60px" show-overflow-tooltip :formatter="row => listenerEventTypeObject[row.event]" /> |
|||
<!-- <el-table-column label="事件id" min-width="70px" prop="id" show-overflow-tooltip />--> |
|||
<el-table-column label="监听类型" width="85px" show-overflow-tooltip :formatter="row => listenerTypeObject[row.listenerType]" /> |
|||
<el-table-column label="操作" > |
|||
<template slot-scope="scope"> |
|||
<el-button size="mini" type="primary" @click="openListenerForm(scope.row, scope.$index)">编辑</el-button> |
|||
<el-divider direction="vertical" /> |
|||
<el-button size="mini" type="danger" @click="removeListener(scope.row, scope.$index)">移除</el-button> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
<div class="element-drawer__button_save"> |
|||
<el-button type="primary" icon="el-icon-plus" size="small" @click="listenerSystemVisible = true">内置监听器</el-button> |
|||
<el-button type="primary" icon="el-icon-plus" size="small" @click="openListenerForm(null)">自定义监听器</el-button> |
|||
</div> |
|||
|
|||
<!-- 监听器 编辑/创建 部分 --> |
|||
<el-drawer :visible.sync="listenerFormModelVisible" title="任务监听器" size="480px" append-to-body destroy-on-close> |
|||
<el-form :model="listenerForm" size="small" label-width="110px" ref="listenerFormRef" @submit.native.prevent> |
|||
<el-form-item prop="event" :rules="{ required: true, trigger: ['blur', 'change'] }"> |
|||
<template slot="label"> |
|||
<span> |
|||
事件类型 |
|||
<el-tooltip placement="top"> |
|||
<template slot="content"> |
|||
<div> |
|||
create(创建):当任务已经创建,并且所有任务参数都已经设置时触发。 |
|||
<br />assignment(指派):当任务已经指派给某人时触发。请注意:当流程执行到达用户任务时, |
|||
<br />在触发create事件之前,会首先触发assignment事件。这顺序看起来不太自然, |
|||
<br />但是有实际原因的:当收到create事件时,我们通常希望能看到任务的所有参数,包括办理人。 |
|||
<br />complete(完成):当任务已经完成,从运行时数据中删除前触发。 |
|||
<br />delete(删除):在任务即将被删除前触发。请注意任务由completeTask正常完成时也会触发。 |
|||
</div> |
|||
</template> |
|||
<i class="el-icon-question" /> |
|||
</el-tooltip> |
|||
</span> |
|||
</template> |
|||
<el-select v-model="listenerForm.event"> |
|||
<el-option v-for="i in Object.keys(listenerEventTypeObject)" :key="i" :label="listenerEventTypeObject[i]" :value="i" /> |
|||
</el-select> |
|||
</el-form-item> |
|||
<!-- <el-form-item label="监听器ID" prop="id" :rules="{ required: true, trigger: ['blur', 'change'] }">--> |
|||
<!-- <el-input v-model="listenerForm.id" clearable />--> |
|||
<!-- </el-form-item>--> |
|||
<el-form-item label="监听器类型" prop="listenerType" :rules="{ required: true, trigger: ['blur', 'change'] }"> |
|||
<template slot="label"> |
|||
<span> |
|||
监听类型 |
|||
<el-tooltip placement="top"> |
|||
<template slot="content"> |
|||
<div> |
|||
class:需要调用的委托类。这个类必须实现org.flowable.engine.delegate.TaskListener接口。 |
|||
<br />assignment(指派):当任务已经指派给某人时触发。请注意:当流程执行到达用户任务时, |
|||
<br /> 在触发create事件之前,会首先触发assignment事件。这顺序看起来不太自然, |
|||
<br /> 但是有实际原因的:当收到create事件时,我们通常希望能看到任务的所有参数,包括办理人。 |
|||
<br />complete(完成):当任务已经完成,从运行时数据中删除前触发。 |
|||
<br />delete(删除):在任务即将被删除前触发。请注意任务由completeTask正常完成时也会触发。 |
|||
</div> |
|||
</template> |
|||
<i class="el-icon-question" /> |
|||
</el-tooltip> |
|||
</span> |
|||
</template> |
|||
<el-select v-model="listenerForm.listenerType"> |
|||
<el-option v-for="i in Object.keys(listenerTypeObject)" :key="i" :label="listenerTypeObject[i]" :value="i" /> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item |
|||
v-if="listenerForm.listenerType === 'classListener'" |
|||
label="Java类" |
|||
prop="class" |
|||
key="listener-class" |
|||
:rules="{ required: true, trigger: ['blur', 'change'] }" |
|||
> |
|||
<el-input v-model="listenerForm.class" clearable /> |
|||
</el-form-item> |
|||
<el-form-item |
|||
v-if="listenerForm.listenerType === 'expressionListener'" |
|||
label="表达式" |
|||
prop="expression" |
|||
key="listener-expression" |
|||
:rules="{ required: true, trigger: ['blur', 'change'] }" |
|||
> |
|||
<el-input v-model="listenerForm.expression" clearable /> |
|||
</el-form-item> |
|||
<el-form-item |
|||
v-if="listenerForm.listenerType === 'delegateExpressionListener'" |
|||
label="代理表达式" |
|||
prop="delegateExpression" |
|||
key="listener-delegate" |
|||
:rules="{ required: true, trigger: ['blur', 'change'] }" |
|||
> |
|||
<el-input v-model="listenerForm.delegateExpression" clearable /> |
|||
</el-form-item> |
|||
<template v-if="listenerForm.listenerType === 'scriptListener'"> |
|||
<el-form-item |
|||
label="脚本格式" |
|||
prop="scriptFormat" |
|||
key="listener-script-format" |
|||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写脚本格式' }" |
|||
> |
|||
<el-input v-model="listenerForm.scriptFormat" clearable /> |
|||
</el-form-item> |
|||
<el-form-item |
|||
label="脚本类型" |
|||
prop="scriptType" |
|||
key="listener-script-type" |
|||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请选择脚本类型' }" |
|||
> |
|||
<el-select v-model="listenerForm.scriptType"> |
|||
<el-option label="内联脚本" value="inlineScript" /> |
|||
<el-option label="外部脚本" value="externalScript" /> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item |
|||
v-if="listenerForm.scriptType === 'inlineScript'" |
|||
label="脚本内容" |
|||
prop="value" |
|||
key="listener-script" |
|||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写脚本内容' }" |
|||
> |
|||
<el-input v-model="listenerForm.value" clearable /> |
|||
</el-form-item> |
|||
<el-form-item |
|||
v-if="listenerForm.scriptType === 'externalScript'" |
|||
label="资源地址" |
|||
prop="resource" |
|||
key="listener-resource" |
|||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写资源地址' }" |
|||
> |
|||
<el-input v-model="listenerForm.resource" clearable /> |
|||
</el-form-item> |
|||
</template> |
|||
|
|||
<template v-if="listenerForm.event === 'timeout'"> |
|||
<el-form-item label="定时器类型" prop="eventDefinitionType" key="eventDefinitionType"> |
|||
<el-select v-model="listenerForm.eventDefinitionType"> |
|||
<el-option label="日期" value="date" /> |
|||
<el-option label="持续时长" value="duration" /> |
|||
<el-option label="循环" value="cycle" /> |
|||
<el-option label="无" value="null" /> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item |
|||
v-if="!!listenerForm.eventDefinitionType && listenerForm.eventDefinitionType !== 'null'" |
|||
label="定时器" |
|||
prop="eventTimeDefinitions" |
|||
key="eventTimeDefinitions" |
|||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写定时器配置' }" |
|||
> |
|||
<el-input v-model="listenerForm.eventTimeDefinitions" clearable /> |
|||
</el-form-item> |
|||
</template> |
|||
</el-form> |
|||
|
|||
<el-divider /> |
|||
<p class="listener-filed__title"> |
|||
<span><i class="el-icon-menu"></i>注入字段:</span> |
|||
<el-button size="small" type="primary" @click="openListenerFieldForm(null)">添加字段</el-button> |
|||
</p> |
|||
<el-table :data="fieldsListOfListener" size="mini" max-height="240" border fit style="flex: none"> |
|||
<el-table-column label="序号" width="50px" type="index" /> |
|||
<el-table-column label="字段名称" width="80px" prop="name" /> |
|||
<el-table-column label="字段类型" width="80px" show-overflow-tooltip :formatter="row => fieldTypeObject[row.fieldType]" /> |
|||
<el-table-column label="值内容" width="80px" show-overflow-tooltip :formatter="row => row.string || row.expression" /> |
|||
<el-table-column label="操作"> |
|||
<template slot-scope="scope"> |
|||
<el-button size="mini" type="primary" @click="openListenerFieldForm(scope.row, scope.$index)">编辑</el-button> |
|||
<el-divider direction="vertical" /> |
|||
<el-button size="mini" type="danger" @click="removeListenerField(scope.row, scope.$index)">移除</el-button> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
|
|||
<div class="element-drawer__button"> |
|||
<el-button size="small" @click="listenerFormModelVisible = false">取 消</el-button> |
|||
<el-button size="small" type="primary" @click="saveListenerConfig">保 存</el-button> |
|||
</div> |
|||
</el-drawer> |
|||
|
|||
<!-- 注入西段 编辑/创建 部分 --> |
|||
<el-dialog title="字段配置" :visible.sync="listenerFieldFormModelVisible" width="600px" append-to-body destroy-on-close> |
|||
<el-form :model="listenerFieldForm" label-width="96px" ref="listenerFieldFormRef" style="height: 136px" @submit.native.prevent> |
|||
<el-form-item label="字段名称:" prop="name" :rules="{ required: true, trigger: ['blur', 'change'] }"> |
|||
<el-input v-model="listenerFieldForm.name" clearable /> |
|||
</el-form-item> |
|||
<el-form-item label="字段类型:" prop="fieldType" :rules="{ required: true, trigger: ['blur', 'change'] }"> |
|||
<el-select v-model="listenerFieldForm.fieldType"> |
|||
<el-option v-for="i in Object.keys(fieldTypeObject)" :key="i" :label="fieldTypeObject[i]" :value="i" /> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item |
|||
v-if="listenerFieldForm.fieldType === 'string'" |
|||
label="字段值:" |
|||
prop="string" |
|||
key="field-string" |
|||
:rules="{ required: true, trigger: ['blur', 'change'] }" |
|||
> |
|||
<el-input v-model="listenerFieldForm.string" clearable /> |
|||
</el-form-item> |
|||
<el-form-item |
|||
v-if="listenerFieldForm.fieldType === 'expression'" |
|||
label="表达式:" |
|||
prop="expression" |
|||
key="field-expression" |
|||
:rules="{ required: true, trigger: ['blur', 'change'] }" |
|||
> |
|||
<el-input v-model="listenerFieldForm.expression" clearable /> |
|||
</el-form-item> |
|||
</el-form> |
|||
<div slot="footer" class="dialog-footer"> |
|||
<el-button size="small" @click="listenerFieldFormModelVisible= false">取 消</el-button> |
|||
<el-button size="small" type="primary" @click="saveListenerFiled">确 定</el-button> |
|||
</div> |
|||
</el-dialog> |
|||
|
|||
<!-- 内置监听器 --> |
|||
<el-drawer :visible.sync="listenerSystemVisible" title="任务监听器" size="580px" append-to-body destroy-on-close> |
|||
<el-table v-loading="loading" :data="listenerList" @selection-change="handleSelectionChange"> |
|||
<el-table-column type="selection" width="55" align="center" /> |
|||
<el-table-column label="名称" align="center" prop="name" /> |
|||
<el-table-column label="类型" align="center" prop="eventType"/> |
|||
<el-table-column label="监听类型" align="center" prop="valueType"> |
|||
<template slot-scope="scope"> |
|||
<dict-tag :options="dict.type.sys_listener_value_type" :value="scope.row.valueType"/> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column label="执行内容" align="center" prop="value" :show-overflow-tooltip="true"/> |
|||
</el-table> |
|||
|
|||
<pagination |
|||
v-show="total>0" |
|||
:total="total" |
|||
layout="prev, pager, next" |
|||
:page.sync="queryParams.pageNum" |
|||
:limit.sync="queryParams.pageSize" |
|||
@pagination="getList" |
|||
/> |
|||
|
|||
<div class="element-drawer__button"> |
|||
<el-button size="small" @click="listenerSystemVisible = false">取 消</el-button> |
|||
<el-button size="small" type="primary" :disabled="listenerSystemChecked" @click="saveSystemListener">保 存</el-button> |
|||
</div> |
|||
</el-drawer> |
|||
</div> |
|||
</template> |
|||
<script> |
|||
import { listListener } from "@/api/flowable/listener"; |
|||
import { |
|||
changeListenerObject, |
|||
createListenerObject, |
|||
createSystemListenerObject, |
|||
updateElementExtensions |
|||
} from "../common/bpmnUtils"; |
|||
|
|||
import {StrUtil} from "@/utils/StrUtil"; |
|||
|
|||
export default { |
|||
name: "TaskListener", |
|||
// 内置监听器相关信息 |
|||
dicts: ['sys_listener_value_type', 'sys_listener_event_type'], |
|||
/** 组件传值 */ |
|||
props : { |
|||
id: { |
|||
type: String, |
|||
required: true |
|||
}, |
|||
}, |
|||
data() { |
|||
return { |
|||
elementListenersList: [], // 监听器列表 |
|||
listenerForm: {},// 监听器详情表单 |
|||
listenerFormModelVisible: false, // 监听器 编辑 侧边栏显示状态 |
|||
fieldsListOfListener: [], |
|||
bpmnElementListeners: [], |
|||
otherExtensionList: [], |
|||
listenerFieldForm: {}, // 监听器 注入字段 详情表单 |
|||
listenerFieldFormModelVisible: false, // 监听器 注入字段表单弹窗 显示状态 |
|||
editingListenerIndex: -1, // 监听器所在下标,-1 为新增 |
|||
editingListenerFieldIndex: -1, // 字段所在下标,-1 为新增 |
|||
|
|||
listenerList: [], |
|||
checkedListenerData: [], |
|||
listenerSystemVisible: false, |
|||
listenerSystemChecked: true, |
|||
loading: true, |
|||
total: 0, |
|||
listenerTypeObject: { |
|||
classListener: "Java 类", |
|||
expressionListener: "表达式", |
|||
delegateExpressionListener: "代理表达式", |
|||
scriptListener: "脚本" |
|||
}, |
|||
listenerEventTypeObject:{ |
|||
create: "创建", |
|||
assignment: "指派", |
|||
complete: "完成", |
|||
delete: "删除", |
|||
// update: "更新", |
|||
// timeout: "超时" |
|||
}, |
|||
fieldTypeObject:{ |
|||
string: "字符串", |
|||
expression: "表达式" |
|||
}, |
|||
queryParams: { |
|||
pageNum: 1, |
|||
pageSize: 10, |
|||
type: 1, |
|||
}, |
|||
} |
|||
}, |
|||
|
|||
/** 传值监听 */ |
|||
watch: { |
|||
id: { |
|||
handler(newVal) { |
|||
if (StrUtil.isNotBlank(newVal)) { |
|||
this.resetListenersList(); |
|||
} |
|||
}, |
|||
immediate: true, // 立即生效 |
|||
}, |
|||
}, |
|||
created() { |
|||
this.getList(); |
|||
|
|||
}, |
|||
methods: { |
|||
resetListenersList() { |
|||
this.bpmnElementListeners = |
|||
this.modelerStore.element.businessObject?.extensionElements?.values?.filter(ex => ex.$type === `flowable:TaskListener`) ?? []; |
|||
this.elementListenersList = this.bpmnElementListeners.map(listener => this.initListenerType(listener)); |
|||
this.$emit('getTaskListenerCount', this.elementListenersList.length) |
|||
}, |
|||
|
|||
// 打开 监听器详情 侧边栏 |
|||
openListenerForm(listener, index) { |
|||
if (listener) { |
|||
this.listenerForm = this.initListenerForm(listener); |
|||
this.editingListenerIndex = index; |
|||
} else { |
|||
this.listenerForm = {}; |
|||
this.editingListenerIndex = -1; // 标记为新增 |
|||
} |
|||
if (listener && listener.fields) { |
|||
this.fieldsListOfListener = listener.fields.map(field => ({ |
|||
...field, |
|||
fieldType: field.string ? "string" : "expression" |
|||
})); |
|||
} else { |
|||
this.fieldsListOfListener = []; |
|||
this.$set(this.listenerForm, "fields", []); |
|||
} |
|||
// 打开侧边栏并清楚验证状态 |
|||
this.listenerFormModelVisible = true; |
|||
this.$nextTick(() => { |
|||
if (this.$refs["listenerFormRef"]) this.$refs["listenerFormRef"].clearValidate(); |
|||
}); |
|||
}, |
|||
|
|||
// 打开监听器字段编辑弹窗 |
|||
openListenerFieldForm(field, index) { |
|||
this.listenerFieldForm = field ? JSON.parse(JSON.stringify(field)) : {}; |
|||
this.editingListenerFieldIndex = field ? index : -1; |
|||
this.listenerFieldFormModelVisible = true; |
|||
this.$nextTick(() => { |
|||
if (this.$refs["listenerFieldFormRef"]) this.$refs["listenerFieldFormRef"].clearValidate(); |
|||
}); |
|||
}, |
|||
|
|||
// 保存监听器注入字段 |
|||
async saveListenerFiled() { |
|||
let validateStatus = await this.$refs["listenerFieldFormRef"].validate(); |
|||
if (!validateStatus) return; // 验证不通过直接返回 |
|||
if (this.editingListenerFieldIndex === -1) { |
|||
this.fieldsListOfListener.push(this.listenerFieldForm); |
|||
this.listenerForm.fields.push(this.listenerFieldForm); |
|||
} else { |
|||
this.fieldsListOfListener.splice(this.editingListenerFieldIndex, 1, this.listenerFieldForm); |
|||
this.listenerForm.fields.splice(this.editingListenerFieldIndex, 1, this.listenerFieldForm); |
|||
} |
|||
this.listenerFieldFormModelVisible = false; |
|||
this.$nextTick(() => (this.listenerFieldForm = {})); |
|||
}, |
|||
|
|||
// 移除监听器字段 |
|||
removeListenerField(field, index) { |
|||
this.$confirm("确认移除该字段吗?", "提示", { |
|||
confirmButtonText: "确 认", |
|||
cancelButtonText: "取 消" |
|||
}).then(() => { |
|||
this.fieldsListOfListener.splice(index, 1); |
|||
this.listenerForm.fields.splice(index, 1); |
|||
}).catch(() => console.info("操作取消")); |
|||
}, |
|||
|
|||
// 移除监听器 |
|||
removeListener(listener, index) { |
|||
this.$confirm("确认移除该监听器吗?", "提示", { |
|||
confirmButtonText: "确 认", |
|||
cancelButtonText: "取 消" |
|||
}).then(() => { |
|||
this.bpmnElementListeners.splice(index, 1); |
|||
this.elementListenersList.splice(index, 1); |
|||
updateElementExtensions(this.modelerStore.moddle, this.modelerStore.modeling, this.modelerStore.element, this.otherExtensionList.concat(this.bpmnElementListeners)); |
|||
this.$emit('getTaskListenerCount', this.elementListenersList.length) |
|||
}).catch((r) => console.info(r, "操作取消")); |
|||
}, |
|||
|
|||
// 保存监听器配置 |
|||
async saveListenerConfig() { |
|||
let validateStatus = await this.$refs["listenerFormRef"].validate(); |
|||
if (!validateStatus) return; // 验证不通过直接返回 |
|||
const listenerObject = createListenerObject(this.modelerStore.moddle, this.listenerForm, false, "flowable"); |
|||
if (this.editingListenerIndex === -1) { |
|||
this.bpmnElementListeners.push(listenerObject); |
|||
this.elementListenersList.push(this.listenerForm); |
|||
} else { |
|||
this.bpmnElementListeners.splice(this.editingListenerIndex, 1, listenerObject); |
|||
this.elementListenersList.splice(this.editingListenerIndex, 1, this.listenerForm); |
|||
} |
|||
// 保存其他配置 |
|||
this.otherExtensionList = this.modelerStore.element.businessObject?.extensionElements?.values?.filter(ex => ex.$type !== `flowable:TaskListener`) ?? []; |
|||
updateElementExtensions(this.modelerStore.moddle, this.modelerStore.modeling, this.modelerStore.element, this.otherExtensionList.concat(this.bpmnElementListeners)); |
|||
this.$emit('getTaskListenerCount', this.elementListenersList.length) |
|||
// 4. 隐藏侧边栏 |
|||
this.listenerFormModelVisible = false; |
|||
this.listenerForm = {}; |
|||
}, |
|||
|
|||
initListenerType(listener) { |
|||
let listenerType; |
|||
if (listener.class) listenerType = "classListener"; |
|||
if (listener.expression) listenerType = "expressionListener"; |
|||
if (listener.delegateExpression) listenerType = "delegateExpressionListener"; |
|||
if (listener.script) listenerType = "scriptListener"; |
|||
return { |
|||
...JSON.parse(JSON.stringify(listener)), |
|||
...(listener.script ?? {}), |
|||
listenerType: listenerType |
|||
}; |
|||
}, |
|||
|
|||
// 初始化表单数据 |
|||
initListenerForm(listener) { |
|||
let self = { |
|||
...listener |
|||
}; |
|||
if (listener.script) { |
|||
self = { |
|||
...listener, |
|||
...listener.script, |
|||
scriptType: listener.script.resource ? "externalScript" : "inlineScript" |
|||
}; |
|||
} |
|||
if (listener.event === "timeout" && listener.eventDefinitions) { |
|||
if (listener.eventDefinitions.length) { |
|||
let k = ""; |
|||
for (let key in listener.eventDefinitions[0]) { |
|||
console.log(listener.eventDefinitions, key); |
|||
if (key.indexOf("time") !== -1) { |
|||
k = key; |
|||
self.eventDefinitionType = key.replace("time", "").toLowerCase(); |
|||
} |
|||
} |
|||
console.log(k); |
|||
self.eventTimeDefinitions = listener.eventDefinitions[0][k].body; |
|||
} |
|||
} |
|||
return self; |
|||
}, |
|||
|
|||
|
|||
/** 查询流程达式列表 */ |
|||
getList() { |
|||
this.loading = true; |
|||
listListener(this.queryParams).then(response => { |
|||
this.listenerList = response.rows; |
|||
this.total = response.total; |
|||
this.loading = false; |
|||
}); |
|||
}, |
|||
|
|||
// 多选框选中数据 |
|||
handleSelectionChange(selection) { |
|||
// ids.value = selection.map(item => item.id); |
|||
// TODO 应该使用 push? |
|||
this.checkedListenerData = selection; |
|||
this.listenerSystemChecked = selection.length !== 1; |
|||
}, |
|||
|
|||
// 保存内置监听器 |
|||
saveSystemListener() { |
|||
if (this.checkedListenerData.length > 0) { |
|||
this.checkedListenerData.forEach(value => { |
|||
// 保存其他配置 |
|||
const listenerObject = createSystemListenerObject(this.modelerStore.moddle, value, true, "flowable"); |
|||
this.bpmnElementListeners.push(listenerObject); |
|||
this.elementListenersList.push(changeListenerObject(value)); |
|||
this.otherExtensionList = this.modelerStore.element.businessObject?.extensionElements?.values?.filter(ex => ex.$type !== `flowable:TaskListener`) ?? []; |
|||
updateElementExtensions(this.modelerStore.moddle, this.modelerStore.modeling, this.modelerStore.element, this.otherExtensionList.concat(this.bpmnElementListeners)); |
|||
}) |
|||
// 回传显示数量 |
|||
this.$emit('getTaskListenerCount', this.elementListenersList.length) |
|||
} |
|||
this.checkedListenerData = []; |
|||
this.listenerSystemChecked = true; |
|||
// 隐藏侧边栏 |
|||
this.listenerSystemVisible = false; |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss"> |
|||
@import '../style/process-panel'; |
|||
.flow-containers .el-badge__content.is-fixed { |
|||
top: 18px; |
|||
} |
|||
.dialog-footer button:first-child { |
|||
margin-right: 10px; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,424 @@ |
|||
<template> |
|||
<div> |
|||
<el-form label-width="80px" size="small"> |
|||
<el-form-item label="异步"> |
|||
<el-switch v-model="bpmnFormData.async" active-text="是" inactive-text="否" @change="updateElementTask('async')"/> |
|||
</el-form-item> |
|||
<el-form-item label="用户类型"> |
|||
<el-select v-model="bpmnFormData.userType" placeholder="选择人员" @change="updateUserType"> |
|||
<el-option |
|||
v-for="item in userTypeOption" |
|||
:key="item.value" |
|||
:label="item.label" |
|||
:value="item.value" |
|||
/> |
|||
</el-select> |
|||
</el-form-item> |
|||
|
|||
<el-form-item label="指定人员" v-if="bpmnFormData.userType === 'assignee'"> |
|||
<el-input-tag v-model="bpmnFormData.assignee" :value="bpmnFormData.assignee"/> |
|||
<el-button-group class="ml-4" style="margin-top: 4px"> |
|||
<!--指定人员--> |
|||
<el-tooltip class="box-item" effect="dark" content="指定人员" placement="bottom"> |
|||
<el-button size="mini" type="primary" icon="el-icon-user" @click="singleUserCheck"/> |
|||
</el-tooltip> |
|||
<!--选择表达式--> |
|||
<el-tooltip class="box-item" effect="dark" content="选择表达式" placement="bottom"> |
|||
<el-button size="mini" type="warning" icon="el-icon-postcard" @click="singleExpCheck"/> |
|||
</el-tooltip> |
|||
</el-button-group> |
|||
</el-form-item> |
|||
|
|||
<el-form-item label="候选人员" v-else-if="bpmnFormData.userType === 'candidateUsers'"> |
|||
<el-input-tag v-model="bpmnFormData.candidateUsers" :value="bpmnFormData.candidateUsers"/> |
|||
<el-button-group class="ml-4" style="margin-top: 4px"> |
|||
<!--候选人员--> |
|||
<el-tooltip class="box-item" effect="dark" content="候选人员" placement="bottom"> |
|||
<el-button size="mini" type="primary" icon="el-icon-user" @click="multipleUserCheck"/> |
|||
</el-tooltip> |
|||
<!--选择表达式--> |
|||
<el-tooltip class="box-item" effect="dark" content="选择表达式" placement="bottom"> |
|||
<el-button size="mini" type="warning" icon="el-icon-postcard" @click="singleExpCheck"/> |
|||
</el-tooltip> |
|||
</el-button-group> |
|||
</el-form-item> |
|||
|
|||
<el-form-item label="候选角色" v-else> |
|||
<el-input-tag v-model="bpmnFormData.candidateGroups" :value="bpmnFormData.candidateGroups"/> |
|||
<el-button-group class="ml-4" style="margin-top: 4px"> |
|||
<!--候选角色--> |
|||
<el-tooltip class="box-item" effect="dark" content="候选角色" placement="bottom"> |
|||
<el-button size="mini" type="primary" icon="el-icon-user" @click="multipleRoleCheck"/> |
|||
</el-tooltip> |
|||
<!--选择表达式--> |
|||
<el-tooltip class="box-item" effect="dark" content="选择表达式" placement="bottom"> |
|||
<el-button size="mini" type="warning" icon="el-icon-postcard" @click="singleExpCheck"/> |
|||
</el-tooltip> |
|||
</el-button-group> |
|||
</el-form-item> |
|||
|
|||
<el-form-item label="优先级"> |
|||
<el-input v-model="bpmnFormData.priority" @change="updateElementTask('priority')"/> |
|||
</el-form-item> |
|||
<el-form-item label="到期时间"> |
|||
<el-input v-model="bpmnFormData.dueDate" @change="updateElementTask('dueDate')"/> |
|||
</el-form-item> |
|||
</el-form> |
|||
|
|||
<!--选择人员--> |
|||
<el-dialog |
|||
title="选择人员" |
|||
:visible.sync="userVisible" |
|||
width="60%" |
|||
:close-on-press-escape="false" |
|||
:show-close="false" |
|||
> |
|||
<flow-user v-if="userVisible" :checkType="checkType" :selectValues="selectData.assignee || selectData.candidateUsers" @handleUserSelect="userSelect"></flow-user> |
|||
<div slot="footer" class="dialog-footer"> |
|||
<el-button size="small" @click="userVisible = false">取 消</el-button> |
|||
<el-button size="small" type="primary" @click="checkUserComplete">确 定</el-button> |
|||
</div> |
|||
</el-dialog> |
|||
|
|||
<!--选择角色--> |
|||
<el-dialog |
|||
title="选择候选角色" |
|||
:visible.sync="roleVisible" |
|||
width="60%" |
|||
:close-on-press-escape="false" |
|||
:show-close="false" |
|||
> |
|||
<flow-role v-if="roleVisible" :selectValues="selectData.candidateGroups" @handleRoleSelect="roleSelect"></flow-role> |
|||
<div slot="footer" class="dialog-footer"> |
|||
<el-button size="small" @click="roleVisible = false">取 消</el-button> |
|||
<el-button size="small" type="primary" @click="checkRoleComplete">确 定</el-button> |
|||
</div> |
|||
</el-dialog> |
|||
|
|||
<!--选择表达式--> |
|||
<el-dialog |
|||
title="选择表达式" |
|||
:visible.sync="expVisible" |
|||
width="60%" |
|||
:close-on-press-escape="false" |
|||
:show-close="false" |
|||
> |
|||
<flow-exp v-if="expVisible" :selectValues="selectData.exp" @handleSingleExpSelect="expSelect"></flow-exp> |
|||
<div slot="footer" class="dialog-footer"> |
|||
<el-button size="small" @click="expVisible = false">取 消</el-button> |
|||
<el-button size="small" type="primary" @click="checkExpComplete">确 定</el-button> |
|||
</div> |
|||
</el-dialog> |
|||
|
|||
|
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import FlowUser from '@/components/flow/User' |
|||
import FlowRole from '@/components/flow/Role' |
|||
import FlowExp from '@/components/flow/Expression' |
|||
import ElInputTag from '@/components/flow/ElInputTag' |
|||
import {StrUtil} from '@/utils/StrUtil' |
|||
|
|||
export default { |
|||
name: "TaskPanel", |
|||
components: { |
|||
FlowUser, |
|||
FlowRole, |
|||
FlowExp, |
|||
ElInputTag |
|||
}, |
|||
/** 组件传值 */ |
|||
props : { |
|||
id: { |
|||
type: String, |
|||
required: true |
|||
}, |
|||
}, |
|||
data() { |
|||
return { |
|||
userVisible: false, |
|||
roleVisible: false, |
|||
expVisible: false, |
|||
isIndeterminate: true, |
|||
checkType: 'single', // 选类 |
|||
userType: '', |
|||
userTypeOption: [ |
|||
{label: '指定人员', value: 'assignee'}, |
|||
{label: '候选人员', value: 'candidateUsers'}, |
|||
{label: '候选角色', value: 'candidateGroups'} |
|||
], |
|||
checkAll: false, |
|||
bpmnFormData: { |
|||
userType: "", |
|||
assignee: "", |
|||
candidateUsers: "", |
|||
candidateGroups: "", |
|||
dueDate: "", |
|||
priority: "", |
|||
dataType: "", |
|||
expId: "", |
|||
}, |
|||
// 数据回显 |
|||
selectData: { |
|||
assignee: null, |
|||
candidateUsers: null, |
|||
candidateGroups: null, |
|||
exp: null, |
|||
}, |
|||
otherExtensionList:[], |
|||
} |
|||
}, |
|||
|
|||
/** 传值监听 */ |
|||
watch: { |
|||
id: { |
|||
handler(newVal) { |
|||
if (StrUtil.isNotBlank(newVal)) { |
|||
this.resetTaskForm(); |
|||
} |
|||
}, |
|||
immediate: true, // 立即生效 |
|||
}, |
|||
}, |
|||
created() { |
|||
|
|||
}, |
|||
methods: { |
|||
// 初始化表单 |
|||
resetTaskForm() { |
|||
// 初始化设为空值 |
|||
this.bpmnFormData = { |
|||
userType: "", |
|||
assignee: "", |
|||
candidateUsers: "", |
|||
candidateGroups: "", |
|||
dueDate: "", |
|||
priority: "", |
|||
dataType: "", |
|||
expId: "", |
|||
} |
|||
this.selectData = { |
|||
assignee: null, |
|||
candidateUsers: null, |
|||
candidateGroups: null, |
|||
exp: null, |
|||
} |
|||
// 流程节点信息上取值 |
|||
for (let key in this.bpmnFormData) { |
|||
const value = this.modelerStore.element?.businessObject[key] || this.bpmnFormData[key]; |
|||
this.$set(this.bpmnFormData, key, value); |
|||
} |
|||
// 人员信息回显 |
|||
this.checkValuesEcho(this.bpmnFormData); |
|||
}, |
|||
|
|||
// 更新节点信息 |
|||
updateElementTask(key) { |
|||
const taskAttr = Object.create(null); |
|||
taskAttr[key] = this.bpmnFormData[key] || ""; |
|||
this.modelerStore.modeling.updateProperties(this.modelerStore.element, taskAttr); |
|||
}, |
|||
|
|||
// 更新自定义流程节点/参数信息 |
|||
updateCustomElement(key, value) { |
|||
const taskAttr = Object.create(null); |
|||
taskAttr[key] = value; |
|||
this.modelerStore.modeling.updateProperties(this.modelerStore.element, taskAttr); |
|||
}, |
|||
|
|||
// 更新人员类型 |
|||
updateUserType(val) { |
|||
// 删除xml中已选择数据类型节点 |
|||
this.deleteFlowAttar(); |
|||
delete this.modelerStore.element.businessObject[`userType`] |
|||
// 清除已选人员数据 |
|||
this.bpmnFormData[val] = null; |
|||
this.selectData = { |
|||
assignee: null, |
|||
candidateUsers: null, |
|||
candidateGroups: null, |
|||
exp: null, |
|||
} |
|||
// 写入userType节点信息到xml |
|||
this.updateCustomElement('userType', val); |
|||
}, |
|||
|
|||
// 设计器右侧表单数据回显 |
|||
checkValuesEcho(formData) { |
|||
if (StrUtil.isNotBlank(formData.expId)) { |
|||
this.getExpList(formData.expId, formData.userType); |
|||
} else { |
|||
if ("candidateGroups" === formData.userType) { |
|||
this.getRoleList(formData[formData.userType], formData.userType); |
|||
} else { |
|||
this.getUserList(formData[formData.userType], formData.userType); |
|||
} |
|||
} |
|||
}, |
|||
|
|||
// 获取表达式信息 |
|||
getExpList(val, key) { |
|||
if (StrUtil.isNotBlank(val)) { |
|||
this.bpmnFormData[key] = this.modelerStore.expList?.find(item => item.id.toString() === val).name; |
|||
this.selectData.exp = this.modelerStore.expList?.find(item => item.id.toString() === val).id; |
|||
} |
|||
}, |
|||
|
|||
// 获取人员信息 |
|||
getUserList(val, key) { |
|||
if (StrUtil.isNotBlank(val)) { |
|||
const newArr = this.modelerStore.userList?.filter(i => val.split(',').includes(i.userId.toString())) |
|||
this.bpmnFormData[key] = newArr.map(item => item.nickName).join(','); |
|||
if ('assignee' === key) { |
|||
this.selectData[key] = newArr.find(item => item.userId.toString() === val).userId; |
|||
} else { |
|||
this.selectData[key] = newArr.map(item => item.userId); |
|||
} |
|||
} |
|||
}, |
|||
|
|||
// 获取角色信息 |
|||
getRoleList(val, key) { |
|||
if (StrUtil.isNotBlank(val)) { |
|||
const newArr = this.modelerStore.roleList?.filter(i => val.split(',').includes(i.roleId.toString())) |
|||
this.bpmnFormData[key] = newArr.map(item => item.roleName).join(','); |
|||
if ('assignee' === key) { |
|||
this.selectData[key] = newArr.find(item => item.roleId.toString() === val).roleId; |
|||
} else { |
|||
this.selectData[key] = newArr.map(item => item.roleId); |
|||
} |
|||
} |
|||
}, |
|||
|
|||
// ------ 流程审批人员信息弹出框 start--------- |
|||
|
|||
/*单选人员*/ |
|||
singleUserCheck() { |
|||
this.userVisible = true; |
|||
this.checkType = "single"; |
|||
}, |
|||
|
|||
/*多选人员*/ |
|||
multipleUserCheck() { |
|||
this.userVisible = true; |
|||
this.checkType = "multiple"; |
|||
}, |
|||
|
|||
/*单选角色*/ |
|||
singleRoleCheck() { |
|||
this.roleVisible = true; |
|||
this.checkType = "single"; |
|||
}, |
|||
|
|||
/*多选角色*/ |
|||
multipleRoleCheck() { |
|||
this.roleVisible = true; |
|||
}, |
|||
|
|||
/*单选表达式*/ |
|||
singleExpCheck() { |
|||
this.expVisible = true; |
|||
}, |
|||
|
|||
// 表达式选中数据 |
|||
expSelect(selection) { |
|||
if (selection) { |
|||
this.deleteFlowAttar(); |
|||
this.bpmnFormData[this.bpmnFormData.userType] = selection.name; |
|||
this.updateCustomElement('dataType', selection.dataType); |
|||
this.updateCustomElement('expId', selection.id.toString()); |
|||
this.updateCustomElement(this.bpmnFormData.userType, selection.expression); |
|||
this.handleSelectData("exp", selection.id); |
|||
} |
|||
}, |
|||
|
|||
// 用户选中数据 TODO: 后面更改为 点击确认按钮再赋值人员信息 |
|||
userSelect(selection) { |
|||
if (selection) { |
|||
this.deleteFlowAttar(); |
|||
this.updateCustomElement('dataType', 'fixed'); |
|||
if (selection instanceof Array) { |
|||
const userIds = selection.map(item => item.userId); |
|||
const nickName = selection.map(item => item.nickName); |
|||
// userType = candidateUsers |
|||
this.bpmnFormData[this.bpmnFormData.userType] = nickName.join(','); |
|||
this.updateCustomElement(this.bpmnFormData.userType, userIds.join(',')); |
|||
this.handleSelectData(this.bpmnFormData.userType, userIds); |
|||
} else { |
|||
// userType = assignee |
|||
this.bpmnFormData[this.bpmnFormData.userType] = selection.nickName; |
|||
this.updateCustomElement(this.bpmnFormData.userType, selection.userId); |
|||
this.handleSelectData(this.bpmnFormData.userType, selection.userId); |
|||
} |
|||
} |
|||
}, |
|||
|
|||
// 角色选中数据 |
|||
roleSelect(selection, name) { |
|||
if (selection && name) { |
|||
this.deleteFlowAttar(); |
|||
this.bpmnFormData[this.bpmnFormData.userType] = name; |
|||
this.updateCustomElement('dataType', 'fixed'); |
|||
// userType = candidateGroups |
|||
this.updateCustomElement(this.bpmnFormData.userType, selection); |
|||
this.handleSelectData(this.bpmnFormData.userType, selection); |
|||
} |
|||
}, |
|||
|
|||
// 处理人员回显 |
|||
handleSelectData(key, value) { |
|||
for (let oldKey in this.selectData) { |
|||
if (key !== oldKey) { |
|||
this.$set(this.selectData, oldKey, null); |
|||
} else { |
|||
this.$set(this.selectData, oldKey, value); |
|||
} |
|||
} |
|||
}, |
|||
|
|||
/*用户选中赋值*/ |
|||
checkUserComplete() { |
|||
this.userVisible = false; |
|||
this.checkType = ""; |
|||
}, |
|||
|
|||
/*候选角色选中赋值*/ |
|||
checkRoleComplete() { |
|||
this.roleVisible = false; |
|||
}, |
|||
|
|||
/*表达式选中赋值*/ |
|||
checkExpComplete() { |
|||
this.expVisible = false; |
|||
}, |
|||
|
|||
// 删除节点 |
|||
deleteFlowAttar() { |
|||
delete this.modelerStore.element.businessObject[`dataType`] |
|||
delete this.modelerStore.element.businessObject[`expId`] |
|||
delete this.modelerStore.element.businessObject[`assignee`] |
|||
delete this.modelerStore.element.businessObject[`candidateUsers`] |
|||
delete this.modelerStore.element.businessObject[`candidateGroups`] |
|||
}, |
|||
|
|||
// 去重数据 |
|||
unique(arr, code) { |
|||
const res = new Map(); |
|||
return arr.filter((item) => !res.has(item[code]) && res.set(item[code], 1)); |
|||
}, |
|||
|
|||
// 更新扩展属性信息 |
|||
updateElementExtensions(properties) { |
|||
const extensions = this.modelerStore.moddle.create("bpmn:ExtensionElements", { |
|||
values: this.otherExtensionList.concat([properties]) |
|||
}); |
|||
|
|||
this.modelerStore.modeling.updateProperties(this.modelerStore.element, { |
|||
extensionElements: extensions |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
@ -0,0 +1,183 @@ |
|||
.my-header { |
|||
display: flex; |
|||
flex-direction: row; |
|||
justify-content: space-between; |
|||
} |
|||
|
|||
.flowMsgPopover { |
|||
display: none; |
|||
} |
|||
|
|||
.tipBox { |
|||
width: 180px; |
|||
background: #fff; |
|||
border-radius: 4px; |
|||
border: 1px solid #ebeef5; |
|||
padding: 12px; |
|||
|
|||
p{ |
|||
line-height: 28px; |
|||
margin:0; |
|||
padding:0; |
|||
} |
|||
} |
|||
|
|||
.cell-item { |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
|
|||
// bpmn 画布 logo |
|||
//.bjs-powered-by { |
|||
// display: none; |
|||
//} |
|||
.view-mode { |
|||
.el-header, .el-aside, .djs-palette, .bjs-powered-by { |
|||
display: none; |
|||
} |
|||
|
|||
.el-loading-mask { |
|||
background-color: initial; |
|||
} |
|||
|
|||
.el-loading-spinner { |
|||
display: none; |
|||
} |
|||
} |
|||
|
|||
.containers { |
|||
width: 100%; |
|||
height: 100%; |
|||
|
|||
.canvas { |
|||
width: 100%; |
|||
height: 100%; |
|||
background: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PHBhdHRlcm4gaWQ9ImEiIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgcGF0dGVyblVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGggZD0iTTAgMTBoNDBNMTAgMHY0ME0wIDIwaDQwTTIwIDB2NDBNMCAzMGg0ME0zMCAwdjQwIiBmaWxsPSJub25lIiBzdHJva2U9IiNlMGUwZTAiIG9wYWNpdHk9Ii4yIi8+PHBhdGggZD0iTTQwIDBIMHY0MCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZTBlMGUwIi8+PC9wYXR0ZXJuPjwvZGVmcz48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSJ1cmwoI2EpIi8+PC9zdmc+") |
|||
} |
|||
|
|||
.panel { |
|||
position: absolute; |
|||
right: 0; |
|||
top: 50px; |
|||
width: 300px; |
|||
} |
|||
|
|||
.load { |
|||
margin-right: 10px; |
|||
} |
|||
|
|||
.djs-palette { |
|||
left: 0px !important; |
|||
top: 0px; |
|||
border-top: none; |
|||
} |
|||
|
|||
.djs-container svg { |
|||
min-height: 650px; |
|||
} |
|||
|
|||
.overlays-div { |
|||
font-size: 10px; |
|||
color: red; |
|||
width: 100px; |
|||
top: -20px !important; |
|||
} |
|||
|
|||
.flow-viewer { |
|||
position: relative; |
|||
padding: 0; |
|||
} |
|||
|
|||
.flow-viewer .button-group { |
|||
display: flex; |
|||
position: absolute; |
|||
width: auto; |
|||
height: auto; |
|||
top: 10px; |
|||
right: 10px; |
|||
} |
|||
|
|||
// 流程线 |
|||
.highlight.djs-shape .djs-visual > :nth-child(1) { |
|||
fill: #56bb56 !important; |
|||
stroke: #56bb56 !important; |
|||
fill-opacity: 0.2 !important; |
|||
} |
|||
|
|||
.highlight.djs-shape .djs-visual > :nth-child(2) { |
|||
fill: #56bb56 !important; |
|||
} |
|||
|
|||
.highlight.djs-shape .djs-visual > path { |
|||
fill: #56bb56 !important; |
|||
fill-opacity: 0.2 !important; |
|||
stroke: #56bb56 !important; |
|||
} |
|||
|
|||
.highlight.djs-connection > .djs-visual > path { |
|||
stroke: #56bb56 !important; |
|||
} |
|||
|
|||
.highlight-todo.djs-connection > .djs-visual > path { |
|||
stroke: #eab24a !important; |
|||
stroke-dasharray: 4px !important; |
|||
fill-opacity: 0.2 !important; |
|||
} |
|||
|
|||
.highlight-todo.djs-shape .djs-visual > :nth-child(1) { |
|||
stroke-dasharray: 5, 5; |
|||
stroke-dashoffset: 500; |
|||
stroke: #eab24a !important; |
|||
fill: rgba(252, 211, 127, 0.2) !important; |
|||
} |
|||
|
|||
@keyframes draw { |
|||
100% { |
|||
stroke-dashoffset: 0; |
|||
} |
|||
} |
|||
|
|||
.process-status { |
|||
position: absolute; |
|||
width: auto; |
|||
height: auto; |
|||
|
|||
display: flex; |
|||
float: right; |
|||
top: 10px; |
|||
left: 10px; |
|||
font-size: 12px; |
|||
|
|||
.intro { |
|||
color: #303133; |
|||
margin-top: 5px; |
|||
} |
|||
|
|||
.finish { |
|||
background-color: #E8FFEA; |
|||
padding: 4px; |
|||
border: 1px solid rgba(0, 180, 42, 0.1); |
|||
border-radius: 3px; |
|||
color: #56bb56; |
|||
margin-right: 8px; |
|||
} |
|||
|
|||
.processing { |
|||
background-color: #fcf5ea; |
|||
padding: 4px; |
|||
border: 1px solid #fce9c7; |
|||
border-radius: 3px; |
|||
color: #eab24a; |
|||
margin-right: 8px; |
|||
} |
|||
|
|||
.todo { |
|||
padding: 4px; |
|||
background: #ECEDEE; |
|||
border: 1px solid rgba(204, 204, 204, 0.1); |
|||
border-radius: 3px; |
|||
color: #666666; |
|||
margin-right: 5px; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,123 @@ |
|||
//.process-panel__container { |
|||
// box-sizing: border-box; |
|||
// padding: 0 8px; |
|||
// border-left: 1px solid #eeeeee; |
|||
// box-shadow: 0 0 8px #cccccc; |
|||
// max-height: 100%; |
|||
// overflow-y: scroll; |
|||
//} |
|||
.panel-tab__title { |
|||
font-weight: 600; |
|||
padding: 0 8px; |
|||
font-size: 1.1em; |
|||
line-height: 1.2em; |
|||
i { |
|||
margin-right: 8px; |
|||
font-size: 1.2em; |
|||
} |
|||
} |
|||
.panel-tab__content { |
|||
width: 100%; |
|||
box-sizing: border-box; |
|||
//border-top: 1px solid #eeeeee; |
|||
padding: 8px 16px; |
|||
.panel-tab__content--title { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
padding-bottom: 8px; |
|||
span { |
|||
flex: 1; |
|||
text-align: left; |
|||
} |
|||
} |
|||
} |
|||
.element-property { |
|||
width: 100%; |
|||
display: flex; |
|||
align-items: flex-start; |
|||
margin: 8px 0; |
|||
.element-property__label { |
|||
display: block; |
|||
width: 90px; |
|||
text-align: right; |
|||
overflow: hidden; |
|||
padding-right: 12px; |
|||
line-height: 32px; |
|||
font-size: 14px; |
|||
box-sizing: border-box; |
|||
} |
|||
.element-property__value { |
|||
flex: 1; |
|||
line-height: 32px; |
|||
} |
|||
.el-form-item { |
|||
width: 100%; |
|||
margin-bottom: 0; |
|||
padding-bottom: 18px; |
|||
} |
|||
} |
|||
.list-property { |
|||
flex-direction: column; |
|||
.element-listener-item { |
|||
width: 100%; |
|||
display: inline-grid; |
|||
grid-template-columns: 16px auto 32px 32px; |
|||
grid-column-gap: 8px; |
|||
} |
|||
.element-listener-item + .element-listener-item { |
|||
margin-top: 8px; |
|||
} |
|||
} |
|||
.listener-filed__title { |
|||
width: 100%; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
margin-top: 0; |
|||
span { |
|||
font-size: 14px; |
|||
} |
|||
i { |
|||
margin-right: 8px; |
|||
} |
|||
} |
|||
.element-drawer__button { |
|||
margin-top: 8px; |
|||
display: inline-flex; |
|||
justify-content: space-around; |
|||
} |
|||
.element-drawer__button > .el-button { |
|||
width: 100%; |
|||
} |
|||
|
|||
.element-drawer__button_save { |
|||
margin-top: 8px; |
|||
width: 100%; |
|||
display: inline-flex; |
|||
justify-content: space-around; |
|||
} |
|||
.element-drawer__button_save > .el-button { |
|||
width: 100%; |
|||
} |
|||
|
|||
.el-collapse-item__content { |
|||
padding-bottom: 0; |
|||
} |
|||
.el-input.is-disabled .el-input__inner { |
|||
color: #999999; |
|||
} |
|||
.el-form-item.el-form-item--mini { |
|||
margin-bottom: 0; |
|||
& + .el-form-item { |
|||
margin-top: 16px; |
|||
} |
|||
} |
|||
.el-drawer__header{ |
|||
margin-bottom: 0; |
|||
border-bottom: 1px solid #e8e8e8; |
|||
padding: 16px 16px 8px 16px; |
|||
font-size: 18px; |
|||
color: #303133; |
|||
} |
|||
.el-drawer__body{ |
|||
padding: 10px; |
|||
} |
|||
@ -0,0 +1,191 @@ |
|||
<template> |
|||
<div |
|||
class="el-input-tag input-tag-wrapper" |
|||
:class="[size ? 'el-input-tag--' + size : '']" |
|||
@click="focusTagInput"> |
|||
<el-tag |
|||
v-for="(tag, idx) in innerTags" |
|||
v-bind="$attrs" |
|||
:key="tag" |
|||
:size="size" |
|||
effect="dark" |
|||
closable |
|||
:disable-transitions="false" |
|||
@close="remove(idx)"> |
|||
{{tag}} |
|||
</el-tag> |
|||
<input |
|||
v-if="!readOnly" |
|||
class="tag-input" |
|||
:placeholder="placeholder" |
|||
@input="inputTag" |
|||
:value="newTag" |
|||
@keydown.delete.stop = "removeLastTag" |
|||
/> |
|||
<!-- @keydown = "addNew" |
|||
@blur = "addNew"--> |
|||
</div> |
|||
</template> |
|||
|
|||
|
|||
<script> |
|||
import {StrUtil} from '@/utils/StrUtil' |
|||
|
|||
export default { |
|||
name: "ElInputTag", |
|||
/** 组件传值 */ |
|||
props : { |
|||
value: { |
|||
type: String, |
|||
default: "" |
|||
}, |
|||
addTagOnKeys: { |
|||
type: Array, |
|||
default: () => [] |
|||
}, |
|||
size: { |
|||
type: String, |
|||
default: 'small' |
|||
}, |
|||
placeholder: String, |
|||
}, |
|||
data() { |
|||
return { |
|||
newTag :"", |
|||
innerTags :[], |
|||
readOnly :true, |
|||
} |
|||
}, |
|||
/** 传值监听 */ |
|||
watch: { |
|||
value: { |
|||
handler(newVal) { |
|||
if (StrUtil.isNotBlank(newVal)) { |
|||
this.innerTags = newVal.split(','); |
|||
}else { |
|||
this.innerTags = []; |
|||
} |
|||
}, |
|||
immediate: true, // 立即生效 |
|||
}, |
|||
}, |
|||
methods: { |
|||
focusTagInput() { |
|||
if (this.readOnly || !this.$el.querySelector('.tag-input')) { |
|||
return |
|||
} else { |
|||
this.$el.querySelector('.tag-input').focus() |
|||
} |
|||
}, |
|||
|
|||
inputTag(ev) { |
|||
this.newTag = ev.target.value |
|||
}, |
|||
|
|||
addNew(e) { |
|||
if (e && (!this.addTagOnKeys.includes(e.keyCode)) && (e.type !== 'blur')) { |
|||
return |
|||
} |
|||
if (e) { |
|||
e.stopPropagation() |
|||
e.preventDefault() |
|||
} |
|||
let addSuccess = false |
|||
if (this.newTag.includes(',')) { |
|||
this.newTag.split(',').forEach(item => { |
|||
if (this.addTag(item.trim())) { |
|||
addSuccess = true |
|||
} |
|||
}) |
|||
} else { |
|||
if (this.addTag(this.newTag.trim())) { |
|||
addSuccess = true |
|||
} |
|||
} |
|||
if (addSuccess) { |
|||
this.tagChange() |
|||
this.newTag = '' |
|||
} |
|||
}, |
|||
|
|||
addTag(tag) { |
|||
tag = tag.trim() |
|||
if (tag && !this.innerTags.includes(tag)) { |
|||
this.innerTags.push(tag) |
|||
return true |
|||
} |
|||
return false |
|||
}, |
|||
|
|||
remove(index) { |
|||
this.innerTags.splice(index, 1) |
|||
this.tagChange(); |
|||
}, |
|||
|
|||
removeLastTag() { |
|||
if (this.newTag) { |
|||
return |
|||
} |
|||
this.innerTags.pop() |
|||
this.tagChange() |
|||
}, |
|||
|
|||
tagChange() { |
|||
this.$emit('input', this.innerTags) |
|||
} |
|||
} |
|||
} |
|||
|
|||
</script> |
|||
|
|||
<style scoped> |
|||
.el-form-item.is-error .el-input-tag { |
|||
border-color: #f56c6c; |
|||
} |
|||
.input-tag-wrapper { |
|||
position: relative; |
|||
font-size: 14px; |
|||
background-color: #fff; |
|||
background-image: none; |
|||
border-radius: 4px; |
|||
border: 1px solid #dcdfe6; |
|||
box-sizing: border-box; |
|||
color: #606266; |
|||
display: inline-block; |
|||
outline: none; |
|||
padding: 0 10px 0 5px; |
|||
transition: border-color .2s cubic-bezier(.645,.045,.355,1); |
|||
width: 100%; |
|||
} |
|||
.el-tag { |
|||
margin-right: 4px; |
|||
} |
|||
|
|||
.tag-input { |
|||
background: transparent; |
|||
border: 0; |
|||
font-size: inherit; |
|||
outline: none; |
|||
padding-left: 0; |
|||
width: 100px; |
|||
} |
|||
.el-input-tag { |
|||
min-height: 42px; |
|||
} |
|||
.el-input-tag--small { |
|||
min-height: 32px; |
|||
line-height: 32px; |
|||
font-size: 12px; |
|||
} |
|||
|
|||
.el-input-tag--default { |
|||
min-height: 34px; |
|||
line-height: 34px; |
|||
} |
|||
|
|||
.el-input-tag--large { |
|||
min-height: 36px; |
|||
line-height: 36px; |
|||
} |
|||
|
|||
</style> |
|||
@ -1,125 +0,0 @@ |
|||
<template> |
|||
<div> |
|||
<el-row> |
|||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" label-width="68px"> |
|||
<el-form-item label="名称" prop="name"> |
|||
<el-input |
|||
v-model="queryParams.name" |
|||
placeholder="请输入名称" |
|||
clearable |
|||
@keyup.enter.native="handleQuery" |
|||
/> |
|||
</el-form-item> |
|||
<el-form-item label="监听类型" prop="type"> |
|||
<el-select v-model="queryParams.type" placeholder="请选择监听类型" clearable> |
|||
<el-option |
|||
v-for="dict in dict.type.sys_listener_type" |
|||
:key="dict.value" |
|||
:label="dict.label" |
|||
:value="dict.value" |
|||
/> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item> |
|||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> |
|||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> |
|||
</el-form-item> |
|||
</el-form> |
|||
</el-row> |
|||
|
|||
<el-table v-loading="loading" :data="listenerList" @selection-change="handleSelectionChange"> |
|||
<el-table-column type="selection" width="55" align="center"/> |
|||
<el-table-column label="名称" align="center" prop="name"/> |
|||
<el-table-column label="监听类型" align="center" prop="type"> |
|||
<template slot-scope="scope"> |
|||
<dict-tag :options="dict.type.sys_listener_type" :value="scope.row.type"/> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column label="事件类型" align="center" prop="eventType"/> |
|||
<el-table-column label="值类型" align="center" prop="valueType"> |
|||
<template slot-scope="scope"> |
|||
<dict-tag :options="dict.type.sys_listener_value_type" :value="scope.row.valueType"/> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column label="执行内容" align="center" prop="value"/> |
|||
</el-table> |
|||
|
|||
<pagination |
|||
v-show="total>0" |
|||
:total="total" |
|||
:page-sizes="[5,10]" |
|||
:page.sync="queryParams.pageNum" |
|||
:limit.sync="queryParams.pageSize" |
|||
@pagination="getList" |
|||
/> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { listListener } from '@/api/system/listener' |
|||
|
|||
export default { |
|||
name: 'FlowListener', |
|||
dicts: ['sys_listener_value_type', 'sys_listener_type', 'common_status', 'sys_listener_event_type'], |
|||
props: { |
|||
selectValues: { |
|||
type: Number | String | Array, |
|||
default: null, |
|||
required: false |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
/** 遮罩层 */ |
|||
loading: true, |
|||
/** 流程监听表格数据 */ |
|||
listenerList: [], |
|||
/** 总条数 */ |
|||
total: 0, |
|||
/** 查询参数 */ |
|||
queryParams: { |
|||
pageNum: 1, |
|||
pageSize: 5, |
|||
name: null, |
|||
type: null, |
|||
eventType: null, |
|||
valueType: null, |
|||
value: null, |
|||
status: null |
|||
} |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.getList() |
|||
}, |
|||
methods: { |
|||
/** 查询流程监听列表 */ |
|||
getList() { |
|||
this.loading = true |
|||
listListener(this.queryParams).then(response => { |
|||
this.listenerList = response.rows |
|||
this.total = response.total |
|||
this.loading = false |
|||
}) |
|||
}, |
|||
/** 搜索按钮操作 */ |
|||
handleQuery() { |
|||
this.queryParams.pageNum = 1 |
|||
this.getList() |
|||
}, |
|||
/** 重置按钮操作 */ |
|||
resetQuery() { |
|||
this.resetForm('queryForm') |
|||
this.handleQuery() |
|||
}, |
|||
/** 多选框选中数据 */ |
|||
handleSelectionChange(selection) { |
|||
this.$emit('handleSelect', selection) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
|
|||
</style> |
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,297 @@ |
|||
<template> |
|||
<div class="app-container"> |
|||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"> |
|||
<el-form-item label="名称" prop="name"> |
|||
<el-input |
|||
v-model="queryParams.name" |
|||
placeholder="请输入表达式名称" |
|||
clearable |
|||
@keyup.enter.native="handleQuery" |
|||
/> |
|||
</el-form-item> |
|||
<el-form-item label="状态" prop="status"> |
|||
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable> |
|||
<el-option |
|||
v-for="dict in dict.type.sys_common_status" |
|||
:key="dict.value" |
|||
:label="dict.label" |
|||
:value="dict.value" |
|||
/> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item> |
|||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> |
|||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> |
|||
</el-form-item> |
|||
</el-form> |
|||
|
|||
<el-row :gutter="10" class="mb8"> |
|||
<el-col :span="1.5"> |
|||
<el-button |
|||
type="primary" |
|||
plain |
|||
icon="el-icon-plus" |
|||
size="mini" |
|||
@click="handleAdd" |
|||
v-hasPermi="['system:expression:add']" |
|||
>新增</el-button> |
|||
</el-col> |
|||
<el-col :span="1.5"> |
|||
<el-button |
|||
type="success" |
|||
plain |
|||
icon="el-icon-edit" |
|||
size="mini" |
|||
:disabled="single" |
|||
@click="handleUpdate" |
|||
v-hasPermi="['system:expression:edit']" |
|||
>修改</el-button> |
|||
</el-col> |
|||
<el-col :span="1.5"> |
|||
<el-button |
|||
type="danger" |
|||
plain |
|||
icon="el-icon-delete" |
|||
size="mini" |
|||
:disabled="multiple" |
|||
@click="handleDelete" |
|||
v-hasPermi="['system:expression:remove']" |
|||
>删除</el-button> |
|||
</el-col> |
|||
<el-col :span="1.5"> |
|||
<el-button |
|||
type="warning" |
|||
plain |
|||
icon="el-icon-download" |
|||
size="mini" |
|||
@click="handleExport" |
|||
v-hasPermi="['system:expression:export']" |
|||
>导出</el-button> |
|||
</el-col> |
|||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> |
|||
</el-row> |
|||
|
|||
<el-table v-loading="loading" :data="expressionList" @selection-change="handleSelectionChange"> |
|||
<el-table-column type="selection" width="55" align="center" /> |
|||
<el-table-column label="主键" align="center" prop="id" /> |
|||
<el-table-column label="名称" align="center" prop="name" /> |
|||
<el-table-column label="表达式内容" align="center" prop="expression" /> |
|||
<el-table-column label="指定类型" align="center" prop="dataType" > |
|||
<template slot-scope="scope"> |
|||
<dict-tag :options="dict.type.exp_data_type" :value="scope.row.dataType"/> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> |
|||
<template slot-scope="scope"> |
|||
<el-button |
|||
size="mini" |
|||
type="text" |
|||
icon="el-icon-edit" |
|||
@click="handleUpdate(scope.row)" |
|||
v-hasPermi="['system:expression:edit']" |
|||
>修改</el-button> |
|||
<el-button |
|||
size="mini" |
|||
type="text" |
|||
icon="el-icon-delete" |
|||
@click="handleDelete(scope.row)" |
|||
v-hasPermi="['system:expression:remove']" |
|||
>删除</el-button> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
|
|||
<pagination |
|||
v-show="total>0" |
|||
:total="total" |
|||
:page.sync="queryParams.pageNum" |
|||
:limit.sync="queryParams.pageSize" |
|||
@pagination="getList" |
|||
/> |
|||
|
|||
<!-- 添加或修改流程达式对话框 --> |
|||
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body> |
|||
<el-form ref="form" :model="form" :rules="rules" label-width="80px"> |
|||
<el-form-item label="名称" prop="name"> |
|||
<el-input v-model="form.name" placeholder="请输入表达式名称" /> |
|||
</el-form-item> |
|||
<el-form-item label="内容" prop="expression"> |
|||
<el-input v-model="form.expression" placeholder="请输入表达式内容" /> |
|||
</el-form-item> |
|||
<el-form-item label="指定类型" prop="dataType"> |
|||
<el-radio-group v-model="form.dataType"> |
|||
<el-radio |
|||
v-for="dict in dict.type.exp_data_type" |
|||
:key="dict.value" |
|||
:label="dict.value" |
|||
>{{dict.label}}</el-radio> |
|||
</el-radio-group> |
|||
</el-form-item> |
|||
<el-form-item label="状态" prop="status"> |
|||
<el-radio-group v-model="form.status"> |
|||
<el-radio |
|||
v-for="dict in dict.type.sys_common_status" |
|||
:key="dict.value" |
|||
:label="parseInt(dict.value)" |
|||
>{{dict.label}}</el-radio> |
|||
</el-radio-group> |
|||
</el-form-item> |
|||
<el-form-item label="备注" prop="remark"> |
|||
<el-input v-model="form.remark" placeholder="请输入备注" /> |
|||
</el-form-item> |
|||
</el-form> |
|||
<div slot="footer" class="dialog-footer"> |
|||
<el-button type="primary" @click="submitForm">确 定</el-button> |
|||
<el-button @click="cancel">取 消</el-button> |
|||
</div> |
|||
</el-dialog> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { listExpression, getExpression, delExpression, addExpression, updateExpression } from "@/api/flowable/expression"; |
|||
|
|||
export default { |
|||
name: "FlowExp", |
|||
dicts: ['sys_common_status','exp_data_type'], |
|||
data() { |
|||
return { |
|||
// 遮罩层 |
|||
loading: true, |
|||
// 选中数组 |
|||
ids: [], |
|||
// 非单个禁用 |
|||
single: true, |
|||
// 非多个禁用 |
|||
multiple: true, |
|||
// 显示搜索条件 |
|||
showSearch: true, |
|||
// 总条数 |
|||
total: 0, |
|||
// 流程达式表格数据 |
|||
expressionList: [], |
|||
// 弹出层标题 |
|||
title: "", |
|||
// 是否显示弹出层 |
|||
open: false, |
|||
// 查询参数 |
|||
queryParams: { |
|||
pageNum: 1, |
|||
pageSize: 10, |
|||
name: null, |
|||
expression: null, |
|||
status: null, |
|||
}, |
|||
// 表单参数 |
|||
form: { |
|||
dataType: 'fixed' |
|||
}, |
|||
// 表单校验 |
|||
rules: { |
|||
} |
|||
}; |
|||
}, |
|||
created() { |
|||
this.getList(); |
|||
}, |
|||
methods: { |
|||
/** 查询流程达式列表 */ |
|||
getList() { |
|||
this.loading = true; |
|||
listExpression(this.queryParams).then(response => { |
|||
this.expressionList = response.rows; |
|||
this.total = response.total; |
|||
this.loading = false; |
|||
}); |
|||
}, |
|||
// 取消按钮 |
|||
cancel() { |
|||
this.open = false; |
|||
this.reset(); |
|||
}, |
|||
// 表单重置 |
|||
reset() { |
|||
this.form = { |
|||
id: null, |
|||
name: null, |
|||
expression: null, |
|||
createTime: null, |
|||
updateTime: null, |
|||
createBy: null, |
|||
updateBy: null, |
|||
status: null, |
|||
remark: null |
|||
}; |
|||
this.resetForm("form"); |
|||
}, |
|||
/** 搜索按钮操作 */ |
|||
handleQuery() { |
|||
this.queryParams.pageNum = 1; |
|||
this.getList(); |
|||
}, |
|||
/** 重置按钮操作 */ |
|||
resetQuery() { |
|||
this.resetForm("queryForm"); |
|||
this.handleQuery(); |
|||
}, |
|||
// 多选框选中数据 |
|||
handleSelectionChange(selection) { |
|||
this.ids = selection.map(item => item.id) |
|||
this.single = selection.length!==1 |
|||
this.multiple = !selection.length |
|||
}, |
|||
/** 新增按钮操作 */ |
|||
handleAdd() { |
|||
this.reset(); |
|||
this.open = true; |
|||
this.title = "添加流程达式"; |
|||
}, |
|||
/** 修改按钮操作 */ |
|||
handleUpdate(row) { |
|||
this.reset(); |
|||
const id = row.id || this.ids |
|||
getExpression(id).then(response => { |
|||
this.form = response.data; |
|||
this.open = true; |
|||
this.title = "修改流程达式"; |
|||
}); |
|||
}, |
|||
/** 提交按钮 */ |
|||
submitForm() { |
|||
this.$refs["form"].validate(valid => { |
|||
if (valid) { |
|||
if (this.form.id != null) { |
|||
updateExpression(this.form).then(response => { |
|||
this.$modal.msgSuccess("修改成功"); |
|||
this.open = false; |
|||
this.getList(); |
|||
}); |
|||
} else { |
|||
addExpression(this.form).then(response => { |
|||
this.$modal.msgSuccess("新增成功"); |
|||
this.open = false; |
|||
this.getList(); |
|||
}); |
|||
} |
|||
} |
|||
}); |
|||
}, |
|||
/** 删除按钮操作 */ |
|||
handleDelete(row) { |
|||
const ids = row.id || this.ids; |
|||
this.$modal.confirm('是否确认删除流程达式编号为"' + ids + '"的数据项?').then(function() { |
|||
return delExpression(ids); |
|||
}).then(() => { |
|||
this.getList(); |
|||
this.$modal.msgSuccess("删除成功"); |
|||
}).catch(() => {}); |
|||
}, |
|||
/** 导出按钮操作 */ |
|||
handleExport() { |
|||
this.download('system/expression/export', { |
|||
...this.queryParams |
|||
}, `expression_${new Date().getTime()}.xlsx`) |
|||
} |
|||
} |
|||
}; |
|||
</script> |
|||
@ -0,0 +1,335 @@ |
|||
<template> |
|||
<div class="app-container"> |
|||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"> |
|||
<el-form-item label="名称" prop="name"> |
|||
<el-input |
|||
v-model="queryParams.name" |
|||
placeholder="请输入名称" |
|||
clearable |
|||
@keyup.enter.native="handleQuery" |
|||
/> |
|||
</el-form-item> |
|||
<el-form-item label="监听类型" prop="type"> |
|||
<el-select v-model="queryParams.type" placeholder="请选择监听类型" clearable> |
|||
<el-option |
|||
v-for="dict in dict.type.sys_listener_type" |
|||
:key="dict.value" |
|||
:label="dict.label" |
|||
:value="dict.value" |
|||
/> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item> |
|||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> |
|||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> |
|||
</el-form-item> |
|||
</el-form> |
|||
|
|||
<el-row :gutter="10" class="mb8"> |
|||
<el-col :span="1.5"> |
|||
<el-button |
|||
type="primary" |
|||
plain |
|||
icon="el-icon-plus" |
|||
size="mini" |
|||
@click="handleAdd" |
|||
v-hasPermi="['system:listener:add']" |
|||
>新增</el-button> |
|||
</el-col> |
|||
<el-col :span="1.5"> |
|||
<el-button |
|||
type="success" |
|||
plain |
|||
icon="el-icon-edit" |
|||
size="mini" |
|||
:disabled="single" |
|||
@click="handleUpdate" |
|||
v-hasPermi="['system:listener:edit']" |
|||
>修改</el-button> |
|||
</el-col> |
|||
<el-col :span="1.5"> |
|||
<el-button |
|||
type="danger" |
|||
plain |
|||
icon="el-icon-delete" |
|||
size="mini" |
|||
:disabled="multiple" |
|||
@click="handleDelete" |
|||
v-hasPermi="['system:listener:remove']" |
|||
>删除</el-button> |
|||
</el-col> |
|||
<el-col :span="1.5"> |
|||
<el-button |
|||
type="warning" |
|||
plain |
|||
icon="el-icon-download" |
|||
size="mini" |
|||
@click="handleExport" |
|||
v-hasPermi="['system:listener:export']" |
|||
>导出</el-button> |
|||
</el-col> |
|||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> |
|||
</el-row> |
|||
|
|||
<el-table v-loading="loading" :data="listenerList" @selection-change="handleSelectionChange"> |
|||
<el-table-column type="selection" width="55" align="center" /> |
|||
<el-table-column label="名称" align="center" prop="name" /> |
|||
<el-table-column label="监听类型" align="center" prop="type"> |
|||
<template slot-scope="scope"> |
|||
<dict-tag :options="dict.type.sys_listener_type" :value="scope.row.type"/> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column label="事件类型" align="center" prop="eventType"/> |
|||
<el-table-column label="值类型" align="center" prop="valueType"> |
|||
<template slot-scope="scope"> |
|||
<dict-tag :options="dict.type.sys_listener_value_type" :value="scope.row.valueType"/> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column label="执行内容" align="center" prop="value" /> |
|||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> |
|||
<template slot-scope="scope"> |
|||
<el-button |
|||
size="mini" |
|||
type="text" |
|||
icon="el-icon-edit" |
|||
@click="handleUpdate(scope.row)" |
|||
v-hasPermi="['system:listener:edit']" |
|||
>修改</el-button> |
|||
<el-button |
|||
size="mini" |
|||
type="text" |
|||
icon="el-icon-delete" |
|||
@click="handleDelete(scope.row)" |
|||
v-hasPermi="['system:listener:remove']" |
|||
>删除</el-button> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
|
|||
<pagination |
|||
v-show="total>0" |
|||
:total="total" |
|||
:page.sync="queryParams.pageNum" |
|||
:limit.sync="queryParams.pageSize" |
|||
@pagination="getList" |
|||
/> |
|||
|
|||
<!-- 添加或修改流程监听对话框 --> |
|||
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body> |
|||
<el-form ref="form" :model="form" :rules="rules" label-width="80px"> |
|||
<el-form-item label="名称" prop="name"> |
|||
<el-input v-model="form.name" placeholder="请输入名称" /> |
|||
</el-form-item> |
|||
<el-form-item label="监听类型" prop="type"> |
|||
<el-select v-model="form.type" placeholder="请选择监听类型"> |
|||
<el-option |
|||
v-for="dict in dict.type.sys_listener_type" |
|||
:key="dict.value" |
|||
:label="dict.label" |
|||
:value="dict.value" |
|||
></el-option> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item label="事件类型" prop="eventType" v-if="form.type === '1'"> |
|||
<el-select v-model="form.eventType" placeholder="请选择事件类型"> |
|||
<el-option |
|||
v-for="dict in taskListenerEventList" |
|||
:key="dict.value" |
|||
:label="dict.label" |
|||
:value="dict.value" |
|||
></el-option> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item label="事件类型" prop="eventType" v-else> |
|||
<el-select v-model="form.eventType" placeholder="请选择事件类型"> |
|||
<el-option |
|||
v-for="dict in executionListenerEventList" |
|||
:key="dict.value" |
|||
:label="dict.label" |
|||
:value="dict.value" |
|||
></el-option> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item label="值类型" prop="valueType"> |
|||
<el-radio-group v-model="form.valueType"> |
|||
<el-radio |
|||
v-for="dict in dict.type.sys_listener_value_type" |
|||
:key="dict.value" |
|||
:label="dict.value" |
|||
>{{dict.label}}</el-radio> |
|||
</el-radio-group> |
|||
</el-form-item> |
|||
<el-form-item label="执行内容" prop="value"> |
|||
<el-input v-model="form.value" placeholder="请输入执行内容" /> |
|||
</el-form-item> |
|||
</el-form> |
|||
<div slot="footer" class="dialog-footer"> |
|||
<el-button type="primary" @click="submitForm">确 定</el-button> |
|||
<el-button @click="cancel">取 消</el-button> |
|||
</div> |
|||
</el-dialog> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { listListener, getListener, delListener, addListener, updateListener } from "@/api/flowable/listener"; |
|||
|
|||
export default { |
|||
name: "Listener", |
|||
dicts: ['sys_listener_value_type', 'sys_listener_type', 'common_status', 'sys_listener_event_type'], |
|||
data() { |
|||
return { |
|||
// 遮罩层 |
|||
loading: true, |
|||
// 选中数组 |
|||
ids: [], |
|||
// 非单个禁用 |
|||
single: true, |
|||
// 非多个禁用 |
|||
multiple: true, |
|||
// 显示搜索条件 |
|||
showSearch: true, |
|||
// 总条数 |
|||
total: 0, |
|||
// 流程监听表格数据 |
|||
listenerList: [], |
|||
// 弹出层标题 |
|||
title: "", |
|||
// 是否显示弹出层 |
|||
open: false, |
|||
// 查询参数 |
|||
queryParams: { |
|||
pageNum: 1, |
|||
pageSize: 10, |
|||
name: null, |
|||
type: null, |
|||
eventType: null, |
|||
valueType: null, |
|||
value: null, |
|||
status: null, |
|||
}, |
|||
// 表单参数 |
|||
form: {}, |
|||
// 表单校验 |
|||
rules: { |
|||
}, |
|||
taskListenerEventList: [ |
|||
{label: 'create', value: 'create'}, |
|||
{label: 'assignment', value: 'assignment'}, |
|||
{label: 'complete', value: 'complete'}, |
|||
{label: 'delete', value: 'delete'}, |
|||
], |
|||
executionListenerEventList: [ |
|||
{label: 'start', value: 'start'}, |
|||
{label: 'end', value: 'end'}, |
|||
{label: 'take', value: 'take'}, |
|||
], |
|||
}; |
|||
}, |
|||
created() { |
|||
this.getList(); |
|||
}, |
|||
methods: { |
|||
/** 查询流程监听列表 */ |
|||
getList() { |
|||
this.loading = true; |
|||
listListener(this.queryParams).then(response => { |
|||
this.listenerList = response.rows; |
|||
this.total = response.total; |
|||
this.loading = false; |
|||
}); |
|||
}, |
|||
// 取消按钮 |
|||
cancel() { |
|||
this.open = false; |
|||
this.reset(); |
|||
}, |
|||
// 表单重置 |
|||
reset() { |
|||
this.form = { |
|||
id: null, |
|||
name: null, |
|||
type: null, |
|||
eventType: null, |
|||
valueType: null, |
|||
value: null, |
|||
createTime: null, |
|||
updateTime: null, |
|||
createBy: null, |
|||
updateBy: null, |
|||
status: null, |
|||
remark: null |
|||
}; |
|||
this.resetForm("form"); |
|||
}, |
|||
/** 搜索按钮操作 */ |
|||
handleQuery() { |
|||
this.queryParams.pageNum = 1; |
|||
this.getList(); |
|||
}, |
|||
/** 重置按钮操作 */ |
|||
resetQuery() { |
|||
this.resetForm("queryForm"); |
|||
this.handleQuery(); |
|||
}, |
|||
// 多选框选中数据 |
|||
handleSelectionChange(selection) { |
|||
this.ids = selection.map(item => item.id) |
|||
this.single = selection.length!==1 |
|||
this.multiple = !selection.length |
|||
}, |
|||
/** 新增按钮操作 */ |
|||
handleAdd() { |
|||
this.reset(); |
|||
this.open = true; |
|||
this.title = "添加流程监听"; |
|||
}, |
|||
/** 修改按钮操作 */ |
|||
handleUpdate(row) { |
|||
this.reset(); |
|||
const id = row.id || this.ids |
|||
getListener(id).then(response => { |
|||
this.form = response.data; |
|||
this.open = true; |
|||
this.title = "修改流程监听"; |
|||
}); |
|||
}, |
|||
/** 提交按钮 */ |
|||
submitForm() { |
|||
this.$refs["form"].validate(valid => { |
|||
if (valid) { |
|||
if (this.form.id != null) { |
|||
updateListener(this.form).then(response => { |
|||
this.$modal.msgSuccess("修改成功"); |
|||
this.open = false; |
|||
this.getList(); |
|||
}); |
|||
} else { |
|||
addListener(this.form).then(response => { |
|||
this.$modal.msgSuccess("新增成功"); |
|||
this.open = false; |
|||
this.getList(); |
|||
}); |
|||
} |
|||
} |
|||
}); |
|||
}, |
|||
/** 删除按钮操作 */ |
|||
handleDelete(row) { |
|||
const ids = row.id || this.ids; |
|||
this.$modal.confirm('是否确认删除流程监听编号为"' + ids + '"的数据项?').then(function() { |
|||
return delListener(ids); |
|||
}).then(() => { |
|||
this.getList(); |
|||
this.$modal.msgSuccess("删除成功"); |
|||
}).catch(() => {}); |
|||
}, |
|||
/** 导出按钮操作 */ |
|||
handleExport() { |
|||
this.download('system/listener/export', { |
|||
...this.queryParams |
|||
}, `listener_${new Date().getTime()}.xlsx`) |
|||
} |
|||
} |
|||
}; |
|||
</script> |
|||
@ -1,24 +0,0 @@ |
|||
<template> |
|||
<div> |
|||
<flow-view :flowData="flowData"/> |
|||
</div> |
|||
</template> |
|||
<script> |
|||
import FlowView from './flowview' |
|||
|
|||
export default { |
|||
name: "Flow", |
|||
components: { |
|||
FlowView |
|||
}, |
|||
props: { |
|||
flowData: { |
|||
type: Object, |
|||
default: () => {} |
|||
} |
|||
}, |
|||
data() { |
|||
return {}; |
|||
} |
|||
}; |
|||
</script> |
|||
@ -0,0 +1,123 @@ |
|||
<template> |
|||
<div> |
|||
<v-form-designer ref="vfDesigner" :designer-config="designerConfig"> |
|||
<!-- 保存按钮 --> |
|||
<template #customSaveButton> |
|||
<el-button type="text" @click="saveFormJson"><i class="el-icon-s-promotion" />保存</el-button> |
|||
</template> |
|||
</v-form-designer> |
|||
|
|||
<!--系统表单信息--> |
|||
<el-dialog :title="formTitle" :visible.sync="formOpen" width="500px" append-to-body> |
|||
<el-form ref="form" :model="form" :rules="rules" label-width="80px"> |
|||
<el-form-item label="表单名称" prop="formName"> |
|||
<el-input v-model="form.formName" placeholder="请输入表单名称" /> |
|||
</el-form-item> |
|||
<el-form-item label="备注" prop="remark"> |
|||
<el-input v-model="form.remark" placeholder="请输入备注" /> |
|||
</el-form-item> |
|||
</el-form> |
|||
<div slot="footer" class="dialog-footer"> |
|||
<el-button type="primary" @click="submitForm">确 定</el-button> |
|||
<el-button @click="cancel">取 消</el-button> |
|||
</div> |
|||
</el-dialog> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import {addForm, getForm, updateForm} from "@/api/flowable/form"; |
|||
import { StrUtil } from '@/utils/StrUtil' |
|||
|
|||
export default { |
|||
name: "flowForm", |
|||
data() { |
|||
return { |
|||
formTitle: "", |
|||
formOpen: false, |
|||
// 表单校验 |
|||
rules: { |
|||
formName: [ |
|||
{ required: true, message: "表单名称不能为空", trigger: "blur" } |
|||
] |
|||
}, |
|||
// 表单参数 |
|||
form: { |
|||
formId: null, |
|||
formName: null, |
|||
formContent: null, |
|||
remark: null |
|||
}, |
|||
designerConfig: { |
|||
generateSFCButton: false, |
|||
exportCodeButton: false, //是否显示导出代码按钮 |
|||
toolbarMaxWidth: 320, |
|||
toolbarMinWidth: 300, //设计器工具按钮栏最小宽度(单位像素) |
|||
formHeader: false, |
|||
}, |
|||
} |
|||
}, |
|||
mounted() { |
|||
const formId = this.$route.query && this.$route.query.formId; |
|||
if (StrUtil.isNotBlank(formId)) { |
|||
getForm(formId).then(res => { |
|||
this.$nextTick(() => { |
|||
// 加载表单json数据 |
|||
this.$refs.vfDesigner.setFormJson(JSON.parse(res.data.formContent)) |
|||
}) |
|||
this.form = res.data; |
|||
}) |
|||
}else { |
|||
this.$nextTick(() => { |
|||
// 加载表单json数据 |
|||
this.$refs.vfDesigner.setFormJson({"widgetList":[],"formConfig":{"modelName":"formData","refName":"vForm","rulesName":"rules","labelWidth":80,"labelPosition":"left","size":"","labelAlign":"label-left-align","cssCode":"","customClass":"","functions":"","layoutType":"PC","onFormCreated":"","onFormMounted":"","onFormDataChange":"","onFormValidate":""}}) |
|||
}) |
|||
} |
|||
}, |
|||
methods:{ |
|||
// 保存表单数据 |
|||
saveFormJson() { |
|||
let formJson = this.$refs.vfDesigner.getFormJson() |
|||
this.form.formContent = JSON.stringify(formJson); |
|||
this.formOpen = true; |
|||
}, |
|||
/** 提交按钮 */ |
|||
submitForm() { |
|||
this.$refs["form"].validate(valid => { |
|||
if (valid) { |
|||
if (this.form.formId != null) { |
|||
updateForm(this.form).then(response => { |
|||
this.$modal.msgSuccess("修改成功"); |
|||
this.formOpen = false; |
|||
}); |
|||
} else { |
|||
addForm(this.form).then(response => { |
|||
this.$modal.msgSuccess("新增成功"); |
|||
this.formOpen = false; |
|||
}); |
|||
} |
|||
// 关闭当前标签页并返回上个页面 |
|||
const obj = { path: "/flowable/form", query: { t: Date.now()} }; |
|||
this.$tab.closeOpenPage(obj); |
|||
} |
|||
}); |
|||
}, |
|||
// 取消按钮 |
|||
cancel() { |
|||
this.formOpen = false; |
|||
this.reset(); |
|||
}, |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
body { |
|||
margin: 0; /* 如果页面出现垂直滚动条,则加入此行CSS以消除之 */ |
|||
} |
|||
.el-container.main-container{ |
|||
background: #fff; |
|||
margin-left: 0 !important; |
|||
} |
|||
|
|||
</style> |
|||
@ -1,24 +0,0 @@ |
|||
<template> |
|||
<div> |
|||
<flow-view :flowData="flowData"/> |
|||
</div> |
|||
</template> |
|||
<script> |
|||
import FlowView from './flowview' |
|||
|
|||
export default { |
|||
name: "Flow", |
|||
components: { |
|||
FlowView |
|||
}, |
|||
props: { |
|||
flowData: { |
|||
type: Object, |
|||
default: () => {} |
|||
} |
|||
}, |
|||
data() { |
|||
return {}; |
|||
} |
|||
}; |
|||
</script> |
|||
@ -1,238 +0,0 @@ |
|||
<template> |
|||
<div class="containers main-box"> |
|||
<el-button type="success" |
|||
size="small" |
|||
icon="el-icon-zoom-in" |
|||
@click="zoomViewport(true)">放大</el-button> |
|||
<el-button type="warning" |
|||
size="small" |
|||
icon="el-icon-zoom-out" |
|||
@click="zoomViewport(false)">缩小</el-button> |
|||
<el-button type="info" |
|||
size="small" |
|||
icon="el-icon-rank" |
|||
@click="fitViewport">适中</el-button> |
|||
<div class="canvas" ref="flowCanvas"></div> |
|||
</div> |
|||
</template> |
|||
<script> |
|||
import { CustomViewer as BpmnViewer } from "@/components/customBpmn"; |
|||
|
|||
export default { |
|||
name: "FlowView", |
|||
props: { |
|||
flowData: { |
|||
type: Object, |
|||
default: () => {} |
|||
}, |
|||
}, |
|||
data() { |
|||
return { |
|||
bpmnViewer: null |
|||
}; |
|||
}, |
|||
watch: { |
|||
flowData: { |
|||
handler(newVal) { |
|||
if (Object.keys(newVal).length > 0) { |
|||
// 生成实例 |
|||
this.bpmnViewer && this.bpmnViewer.destroy(); |
|||
this.bpmnViewer = new BpmnViewer({ |
|||
container: this.$refs.flowCanvas, |
|||
height: 'calc(100vh - 200px)', |
|||
}); |
|||
this.loadFlowCanvas(newVal); |
|||
} |
|||
}, |
|||
immediate: true, // 立即生效 |
|||
deep: true //监听对象或数组的时候,要用到深度监听 |
|||
} |
|||
}, |
|||
mounted() { |
|||
}, |
|||
methods: { |
|||
// 加载流程 |
|||
async loadFlowCanvas(flowData) { |
|||
const self = this |
|||
try { |
|||
await self.bpmnViewer.importXML(flowData.xmlData); |
|||
self.fitViewport() |
|||
if (flowData.nodeData !==undefined && flowData.nodeData.length > 0 ) { |
|||
self.fillColor(flowData.nodeData) |
|||
} |
|||
} catch (err) { |
|||
console.error(err.message, err.warnings) |
|||
} |
|||
}, |
|||
// 设置高亮颜色的class |
|||
setNodeColor(nodeCodes, colorClass, canvas) { |
|||
for (let i = 0; i < nodeCodes.length; i++) { |
|||
canvas.addMarker(nodeCodes[i], colorClass); |
|||
} |
|||
}, |
|||
// 让图能自适应屏幕 |
|||
fitViewport() { |
|||
this.zoom = this.bpmnViewer.get('canvas').zoom("fit-viewport", "auto") |
|||
}, |
|||
// 放大缩小 |
|||
zoomViewport(zoomIn = true) { |
|||
this.zoom = this.bpmnViewer.get('canvas').zoom() |
|||
this.zoom += (zoomIn ? 0.1 : -0.1) |
|||
if(this.zoom >= 0.2) this.bpmnViewer.get('canvas').zoom(this.zoom) |
|||
}, |
|||
|
|||
// 设置高亮颜色的 |
|||
fillColor(nodeData) { |
|||
const canvas = this.bpmnViewer.get('canvas') |
|||
this.bpmnViewer.getDefinitions().rootElements[0].flowElements.forEach(n => { |
|||
const completeTask = nodeData.find(m => m.key === n.id) |
|||
const todoTask = nodeData.find(m => !m.completed) |
|||
const endTask = nodeData[nodeData.length - 1] |
|||
if (n.$type === 'bpmn:UserTask') { |
|||
if (completeTask) { |
|||
canvas.addMarker(n.id, completeTask.completed ? 'highlight' : 'highlight-todo') |
|||
n.outgoing?.forEach(nn => { |
|||
const targetTask = nodeData.find(m => m.key === nn.targetRef.id) |
|||
if (targetTask) { |
|||
if (todoTask && completeTask.key === todoTask.key && !todoTask.completed){ |
|||
canvas.addMarker(nn.id, todoTask.completed ? 'highlight' : 'highlight-todo') |
|||
canvas.addMarker(nn.targetRef.id, todoTask.completed ? 'highlight' : 'highlight-todo') |
|||
}else { |
|||
canvas.addMarker(nn.id, targetTask.completed ? 'highlight' : 'highlight-todo') |
|||
canvas.addMarker(nn.targetRef.id, targetTask.completed ? 'highlight' : 'highlight-todo') |
|||
} |
|||
} |
|||
}) |
|||
} |
|||
} |
|||
// 排他网关 |
|||
else if (n.$type === 'bpmn:ExclusiveGateway') { |
|||
if (completeTask) { |
|||
canvas.addMarker(n.id, completeTask.completed ? 'highlight' : 'highlight-todo') |
|||
n.outgoing?.forEach(nn => { |
|||
const targetTask = nodeData.find(m => m.key === nn.targetRef.id) |
|||
if (targetTask) { |
|||
|
|||
canvas.addMarker(nn.id, targetTask.completed ? 'highlight' : 'highlight-todo') |
|||
canvas.addMarker(nn.targetRef.id, targetTask.completed ? 'highlight' : 'highlight-todo') |
|||
} |
|||
|
|||
}) |
|||
} |
|||
|
|||
} |
|||
// 并行网关 |
|||
else if (n.$type === 'bpmn:ParallelGateway') { |
|||
if (completeTask) { |
|||
canvas.addMarker(n.id, completeTask.completed ? 'highlight' : 'highlight-todo') |
|||
n.outgoing?.forEach(nn => { |
|||
const targetTask = nodeData.find(m => m.key === nn.targetRef.id) |
|||
if (targetTask) { |
|||
canvas.addMarker(nn.id, targetTask.completed ? 'highlight' : 'highlight-todo') |
|||
canvas.addMarker(nn.targetRef.id, targetTask.completed ? 'highlight' : 'highlight-todo') |
|||
} |
|||
}) |
|||
} |
|||
} |
|||
else if (n.$type === 'bpmn:StartEvent') { |
|||
n.outgoing.forEach(nn => { |
|||
const completeTask = nodeData.find(m => m.key === nn.targetRef.id) |
|||
if (completeTask) { |
|||
canvas.addMarker(nn.id, 'highlight') |
|||
canvas.addMarker(n.id, 'highlight') |
|||
return |
|||
} |
|||
}) |
|||
} |
|||
else if (n.$type === 'bpmn:EndEvent') { |
|||
if (endTask.key === n.id && endTask.completed) { |
|||
canvas.addMarker(n.id, 'highlight') |
|||
return |
|||
} |
|||
} |
|||
}) |
|||
}, |
|||
} |
|||
}; |
|||
</script> |
|||
<style lang="scss"> |
|||
.bjs-powered-by { |
|||
display: none; |
|||
} |
|||
.view-mode { |
|||
.el-header, .el-aside, .djs-palette, .bjs-powered-by { |
|||
display: none; |
|||
} |
|||
.el-loading-mask { |
|||
background-color: initial; |
|||
} |
|||
.el-loading-spinner { |
|||
display: none; |
|||
} |
|||
} |
|||
.containers { |
|||
// background-color: #ffffff; |
|||
width: 100%; |
|||
height: 100%; |
|||
.canvas { |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
.panel { |
|||
position: absolute; |
|||
right: 0; |
|||
top: 50px; |
|||
width: 300px; |
|||
} |
|||
.load { |
|||
margin-right: 10px; |
|||
} |
|||
.el-form-item__label{ |
|||
font-size: 13px; |
|||
} |
|||
|
|||
.djs-palette{ |
|||
left: 0px!important; |
|||
top: 0px; |
|||
border-top: none; |
|||
} |
|||
|
|||
.djs-container svg { |
|||
min-height: 650px; |
|||
} |
|||
|
|||
.highlight.djs-shape .djs-visual > :nth-child(1) { |
|||
fill: green !important; |
|||
stroke: green !important; |
|||
fill-opacity: 0.2 !important; |
|||
} |
|||
.highlight.djs-shape .djs-visual > :nth-child(2) { |
|||
fill: green !important; |
|||
} |
|||
.highlight.djs-shape .djs-visual > path { |
|||
fill: green !important; |
|||
fill-opacity: 0.2 !important; |
|||
stroke: green !important; |
|||
} |
|||
.highlight.djs-connection > .djs-visual > path { |
|||
stroke: green !important; |
|||
} |
|||
.highlight-todo.djs-connection > .djs-visual > path { |
|||
stroke: orange !important; |
|||
stroke-dasharray: 4px !important; |
|||
fill-opacity: 0.2 !important; |
|||
} |
|||
.highlight-todo.djs-shape .djs-visual > :nth-child(1) { |
|||
fill: orange !important; |
|||
stroke: orange !important; |
|||
stroke-dasharray: 4px !important; |
|||
fill-opacity: 0.2 !important; |
|||
} |
|||
.overlays-div { |
|||
font-size: 10px; |
|||
color: red; |
|||
width: 100px; |
|||
top: -20px !important; |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,24 +0,0 @@ |
|||
<template> |
|||
<div> |
|||
<flow-view :flowData="flowData"/> |
|||
</div> |
|||
</template> |
|||
<script> |
|||
import FlowView from './flowview' |
|||
|
|||
export default { |
|||
name: "Flow", |
|||
components: { |
|||
FlowView |
|||
}, |
|||
props: { |
|||
flowData: { |
|||
type: Object, |
|||
default: () => {} |
|||
}, |
|||
}, |
|||
data() { |
|||
return {}; |
|||
} |
|||
}; |
|||
</script> |
|||
@ -1,129 +0,0 @@ |
|||
<template> |
|||
<div class="containers main-box"> |
|||
<el-button type="success" |
|||
size="small" |
|||
icon="el-icon-zoom-in" |
|||
@click="zoomViewport(true)">放大</el-button> |
|||
<el-button type="warning" |
|||
size="small" |
|||
icon="el-icon-zoom-out" |
|||
@click="zoomViewport(false)">缩小</el-button> |
|||
<el-button type="info" |
|||
size="small" |
|||
icon="el-icon-rank" |
|||
@click="fitViewport">适中</el-button> |
|||
<div class="canvas" ref="flowCanvas"></div> |
|||
</div> |
|||
</template> |
|||
<script> |
|||
import { CustomViewer as BpmnViewer } from "@/components/customBpmn"; |
|||
|
|||
export default { |
|||
name: "FlowView", |
|||
props: { |
|||
flowData: { |
|||
type: Object, |
|||
default: () => {} |
|||
}, |
|||
}, |
|||
data() { |
|||
return { |
|||
bpmnViewer: null |
|||
}; |
|||
}, |
|||
watch: { |
|||
flowData: { |
|||
handler(newVal) { |
|||
if (Object.keys(newVal).length > 0) { |
|||
// 生成实例 |
|||
this.bpmnViewer && this.bpmnViewer.destroy(); |
|||
this.bpmnViewer = new BpmnViewer({ |
|||
container: this.$refs.flowCanvas, |
|||
height: 'calc(100vh - 200px)', |
|||
}); |
|||
this.loadFlowCanvas(newVal) |
|||
} |
|||
}, |
|||
immediate: true, // 立即生效 |
|||
deep: true //监听对象或数组的时候,要用到深度监听 |
|||
} |
|||
}, |
|||
mounted() {}, |
|||
methods: { |
|||
// 加载流程图片 |
|||
async loadFlowCanvas(flowData) { |
|||
const self = this |
|||
try { |
|||
await self.bpmnViewer.importXML(flowData.xmlData); |
|||
self.fitViewport() |
|||
} catch (err) { |
|||
console.error(err.message, err.warnings) |
|||
} |
|||
}, |
|||
// 让图能自适应屏幕 |
|||
fitViewport() { |
|||
this.zoom = this.bpmnViewer.get('canvas').zoom("fit-viewport", "auto") |
|||
}, |
|||
// 放大缩小 |
|||
zoomViewport(zoomIn = true) { |
|||
this.zoom = this.bpmnViewer.get('canvas').zoom() |
|||
this.zoom += (zoomIn ? 0.1 : -0.1) |
|||
if(this.zoom >= 0.2) this.bpmnViewer.get('canvas').zoom(this.zoom) |
|||
}, |
|||
} |
|||
}; |
|||
</script> |
|||
<style lang="scss"> |
|||
.bjs-powered-by { |
|||
display: none; |
|||
} |
|||
.view-mode { |
|||
.el-header, .el-aside, .djs-palette, .bjs-powered-by { |
|||
display: none; |
|||
} |
|||
.el-loading-mask { |
|||
background-color: initial; |
|||
} |
|||
.el-loading-spinner { |
|||
display: none; |
|||
} |
|||
} |
|||
.containers { |
|||
// background-color: #ffffff; |
|||
width: 100%; |
|||
height: 100%; |
|||
.canvas { |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
.panel { |
|||
position: absolute; |
|||
right: 0; |
|||
top: 50px; |
|||
width: 300px; |
|||
} |
|||
.load { |
|||
margin-right: 10px; |
|||
} |
|||
.el-form-item__label{ |
|||
font-size: 13px; |
|||
} |
|||
|
|||
.djs-palette{ |
|||
left: 0px!important; |
|||
top: 0px; |
|||
border-top: none; |
|||
} |
|||
|
|||
.djs-container svg { |
|||
min-height: 650px; |
|||
} |
|||
|
|||
.overlays-div { |
|||
font-size: 10px; |
|||
color: red; |
|||
width: 100px; |
|||
top: -20px !important; |
|||
} |
|||
} |
|||
</style> |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue