提交 c9e5476b authored 作者: kxjia's avatar kxjia

修改工作流多实例问题

上级 c90615cf
......@@ -63,7 +63,8 @@ const editableColumns = [
]
const defaultProperties = [
{ name: 'isApprove', value: 'false' }
{ name: 'isApprove', value: 'false' },
{ name: 'isEdit', value: 'false' },
]
onMounted(() => {
......
<template>
<div class="panel-tab__content">
<a-form layout="horizontal" :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }" @submit.prevent size="small">
<a-form-item label="参数说明">
<a-button size="small" type="primary" @click="dialogVisible = true">查看</a-button>
</a-form-item>
<a-form-item label="回路特性">
<a-select v-model:value="loopCharacteristics" @change="changeLoopCharacteristicsType">
<!--bpmn:MultiInstanceLoopCharacteristics-->
<a-select v-model:value="loopCharacteristics" @change="handleLoopTypeChange">
<a-select-option value="ParallelMultiInstance">并行多重事件</a-select-option>
<a-select-option value="SequentialMultiInstance">时序多重事件</a-select-option>
<!--bpmn:StandardLoopCharacteristics-->
<a-select-option value="StandardLoop">循环事件</a-select-option>
<a-select-option value="Null"></a-select-option>
</a-select>
</a-form-item>
<a-form-item label="多实例模式" v-if="loopCharacteristics !== 'Null' && loopCharacteristics !== 'StandardLoop'">
<a-radio-group v-model:value="multiInstanceMode" @change="changeMultiInstanceMode">
<a-form-item label="多实例模式" v-if="loopCharacteristics && loopCharacteristics !== 'Null'">
<a-radio-group v-model:value="multiInstanceMode" @change="handleModeChange">
<a-radio value="counterSign">会签(全部完成)</a-radio>
<a-radio value="orSign">或签(任一完成)</a-radio>
<a-radio value="normal">普通</a-radio>
</a-radio-group>
</a-form-item>
<template v-if="loopCharacteristics === 'ParallelMultiInstance' || loopCharacteristics === 'SequentialMultiInstance'">
<a-form-item label="循环基数" key="loopCardinality">
<a-input v-model:value="loopInstanceForm.loopCardinality" allow-clear @change="updateLoopCardinality" />
<a-form-item label="循环基数">
<a-input v-model:value="loopInstanceForm.loopCardinality" @blur="updateLoopCardinality" />
</a-form-item>
<a-form-item label="集合" key="collection">
<a-input v-model:value="loopInstanceForm.collection" allow-clear @change="updateLoopBase" />
<a-form-item label="集合">
<a-input v-model:value="loopInstanceForm.collection" @blur="updateLoopBase" />
</a-form-item>
<a-form-item label="元素变量" key="elementVariable">
<a-input v-model:value="loopInstanceForm.elementVariable" allow-clear @change="updateLoopBase" />
<a-form-item label="元素变量">
<a-input v-model:value="loopInstanceForm.elementVariable" @blur="updateLoopBase" />
</a-form-item>
<a-form-item label="完成条件" key="completionCondition">
<a-input v-model:value="loopInstanceForm.completionCondition" allow-clear @change="updateLoopCondition" />
<a-form-item label="完成条件">
<a-input v-model:value="loopInstanceForm.completionCondition" @blur="updateLoopCondition" />
</a-form-item>
<a-form-item label="异步状态" key="async">
<a-form-item label="异步状态">
<a-checkbox v-model:checked="loopInstanceForm.asyncBefore" @change="() => updateLoopAsync('asyncBefore')">
异步前
</a-checkbox>
......@@ -49,43 +43,16 @@
排除
</a-checkbox>
</a-form-item>
<a-form-item
label="重试周期"
key="timeCycle"
v-if="loopInstanceForm.asyncAfter || loopInstanceForm.asyncBefore"
>
<a-input v-model:value="loopInstanceForm.timeCycle" allow-clear @change="updateLoopTimeCycle" />
<a-form-item label="重试周期" v-if="loopInstanceForm.asyncAfter || loopInstanceForm.asyncBefore">
<a-input v-model:value="loopInstanceForm.timeCycle" @blur="updateLoopTimeCycle" />
</a-form-item>
</template>
</a-form>
<!-- 参数说明 -->
<a-modal
v-model:open="dialogVisible"
title="多实例参数"
width="680px"
:footer="null"
@cancel="dialogVisible = false"
>
<a-descriptions :column="1" bordered>
<a-descriptions-item label="使用说明">按照BPMN2.0规范的要求,用于为每个实例创建执行的父执行,会提供下列变量:</a-descriptions-item>
<a-descriptions-item label="collection(集合变量)">传入List参数, 一般为用户ID集合</a-descriptions-item>
<a-descriptions-item label="elementVariable(元素变量)">List中单个参数的名称</a-descriptions-item>
<a-descriptions-item label="loopCardinality(基数)">List循环次数</a-descriptions-item>
<a-descriptions-item label="isSequential(串并行)">Parallel: 并行多实例,Sequential: 串行多实例</a-descriptions-item>
<a-descriptions-item label="completionCondition(完成条件)">任务出口条件</a-descriptions-item>
<a-descriptions-item label="nrOfInstances(实例总数)">实例总数</a-descriptions-item>
<a-descriptions-item label="nrOfActiveInstances(未完成数)">当前活动的(即未完成的),实例数量。对于顺序多实例,这个值总为1</a-descriptions-item>
<a-descriptions-item label="nrOfCompletedInstances(已完成数)">已完成的实例数量</a-descriptions-item>
<a-descriptions-item label="loopCounter">给定实例在for-each循环中的index</a-descriptions-item>
</a-descriptions>
</a-modal>
</div>
</template>
<script lang="ts" setup>
import { ref, watch, reactive, nextTick, onMounted } from 'vue'
import { StrUtil } from '../common/StrUtil'
import { ref, watch, reactive, onMounted, toRaw } from 'vue'
import { useModelerStore } from '../store/modeler-store.js'
interface LoopInstanceForm {
......@@ -93,12 +60,10 @@ interface LoopInstanceForm {
loopCardinality?: string
collection?: string
elementVariable?: string
asyncAfter?: boolean
timeCycle?: string
asyncBefore?: boolean
asyncAfter?: boolean
exclusive?: boolean
timeCycle?: string
extensionElements?: any[]
[key: string]: any
}
const props = defineProps<{
......@@ -108,75 +73,104 @@ const props = defineProps<{
const modelerStore = useModelerStore()
// 响应式数据
const dialogVisible = ref(false)
const loopCharacteristics = ref("")
const multiInstanceMode = ref("normal")
const loopInstanceForm = reactive<LoopInstanceForm>({})
const multiLoopInstance = ref<any>(null)
const defaultLoopInstanceForm: LoopInstanceForm = {
completionCondition: "",
loopCardinality: "",
extensionElements: [],
asyncAfter: false,
const loopInstanceForm = reactive<LoopInstanceForm>({
completionCondition: '',
loopCardinality: '',
collection: '',
elementVariable: '',
timeCycle: '',
asyncBefore: false,
asyncAfter: false,
exclusive: false
})
const getBpmnModeler = () => toRaw(modelerStore.modeler)
const getModdle = () => toRaw(modelerStore.moddle)
const getModeling = () => {
const modeler = getBpmnModeler()
if (!modeler) return null
return modeler.get('modeling')
}
const createLoopCharacteristics = (extra?: Record<string, any>) => {
const moddle = getModdle()
const element = toRaw(modelerStore.element)
console.log('[multiInstance] createLoopCharacteristics, element:', element?.id)
console.log('[multiInstance] loopCharacteristics exists:', !!element?.businessObject?.loopCharacteristics)
if (!moddle || !element) return null
const lc = toRaw(element.businessObject?.loopCharacteristics)
console.log('[multiInstance] lc:', lc)
if (!lc) return null
// 监听 id 变化
watch(() => props.id, (newVal) => {
console.log('[multiInstance] id changed:', newVal, 'store element:', modelerStore.element?.id)
if (StrUtil.isNotBlank(newVal) && modelerStore.element) {
nextTick(() => {
getElementLoop(modelerStore.element.businessObject)
let condition = null
if (multiInstanceMode.value === 'counterSign') {
condition = moddle.create("bpmn:FormalExpression", {
body: '${nrOfCompletedInstances >= nrOfInstances}'
})
} else if (multiInstanceMode.value === 'orSign') {
condition = moddle.create("bpmn:FormalExpression", {
body: '${nrOfActiveInstances == 0}'
})
} else if (loopInstanceForm.completionCondition) {
condition = moddle.create("bpmn:FormalExpression", { body: loopInstanceForm.completionCondition })
}
}, { immediate: true })
onMounted(() => {
console.log('[multiInstance] mounted, id:', props.id, 'store element:', modelerStore.element?.id)
if (props.id && modelerStore.element) {
getElementLoop(modelerStore.element.businessObject)
let cardinality = null
if (loopInstanceForm.loopCardinality) {
cardinality = moddle.create("bpmn:FormalExpression", { body: loopInstanceForm.loopCardinality })
}
})
// 获取元素循环配置
const getElementLoop = (businessObject: any) => {
if (!businessObject.loopCharacteristics) {
return moddle.create("bpmn:MultiInstanceLoopCharacteristics", {
isSequential: lc.isSequential,
loopCardinality: cardinality,
completionCondition: condition,
collection: loopInstanceForm.collection,
elementVariable: loopInstanceForm.elementVariable,
asyncBefore: loopInstanceForm.asyncBefore,
asyncAfter: loopInstanceForm.asyncAfter,
exclusive: loopInstanceForm.exclusive,
...extra
})
}
const loadElementData = () => {
const element = toRaw(modelerStore.element)
if (!element?.businessObject) return
const bo = toRaw(element.businessObject)
if (!bo?.loopCharacteristics) {
loopCharacteristics.value = "Null"
Object.assign(loopInstanceForm, {})
return
}
if (businessObject.loopCharacteristics.$type === "bpmn:StandardLoopCharacteristics") {
loopCharacteristics.value = "StandardLoop"
Object.assign(loopInstanceForm, {})
return
}
const lc = toRaw(bo.loopCharacteristics)
if (!lc) return
if (businessObject.loopCharacteristics.isSequential) {
if (lc.isSequential) {
loopCharacteristics.value = "SequentialMultiInstance"
} else {
loopCharacteristics.value = "ParallelMultiInstance"
}
// 合并配置
Object.assign(loopInstanceForm, {
...defaultLoopInstanceForm,
...businessObject.loopCharacteristics,
completionCondition: businessObject.loopCharacteristics?.completionCondition?.body ?? "",
loopCardinality: businessObject.loopCharacteristics?.loopCardinality?.body ?? ""
})
// 读取多实例模式
if (businessObject.loopCharacteristics?.completionCondition) {
const condition = businessObject.loopCharacteristics.completionCondition?.body || ''
if (condition.includes('${nrOfCompletedInstances') && condition.includes('nrOfInstances')) {
loopInstanceForm.loopCardinality = lc.loopCardinality?.body || ''
loopInstanceForm.collection = lc.collection || ''
loopInstanceForm.elementVariable = lc.elementVariable || ''
loopInstanceForm.completionCondition = lc.completionCondition?.body || ''
loopInstanceForm.asyncBefore = lc.asyncBefore || false
loopInstanceForm.asyncAfter = lc.asyncAfter || false
loopInstanceForm.exclusive = lc.exclusive || false
if (lc.completionCondition?.body) {
const body = lc.completionCondition.body
if (body && body.includes('nrOfCompletedInstances')) {
multiInstanceMode.value = 'counterSign'
} else if (condition.includes('${nrOfActiveInstances') === 0) {
} else if (body && body.includes('nrOfActiveInstances')) {
multiInstanceMode.value = 'orSign'
} else {
multiInstanceMode.value = 'normal'
......@@ -184,141 +178,161 @@ const getElementLoop = (businessObject: any) => {
} else {
multiInstanceMode.value = 'normal'
}
// 保留当前元素 businessObject 上的 loopCharacteristics 实例
multiLoopInstance.value = businessObject.loopCharacteristics
// 更新表单
if (
businessObject.loopCharacteristics.extensionElements &&
businessObject.loopCharacteristics.extensionElements.values &&
businessObject.loopCharacteristics.extensionElements.values.length
) {
loopInstanceForm.timeCycle = businessObject.loopCharacteristics.extensionElements.values[0].body
}
}
// 改变循环特性类型
const changeLoopCharacteristicsType = (type: string) => {
// 切换类型取消原表单配置
Object.assign(loopInstanceForm, defaultLoopInstanceForm)
const handleLoopTypeChange = (type: string) => {
const modeler = getBpmnModeler()
const moddle = getModdle()
const element = toRaw(modelerStore.element)
const modeling = getModeling()
// 取消多实例配置
if (type === "Null") {
modelerStore.modeling.updateProperties(modelerStore.element, { loopCharacteristics: null })
return
}
if (!modeling || !moddle || !element) return
// 配置循环
if (type === "StandardLoop") {
const loopCharacteristicsObject = modelerStore.moddle.create("bpmn:StandardLoopCharacteristics")
modelerStore.modeling.updateProperties(modelerStore.element, {
loopCharacteristics: loopCharacteristicsObject
})
multiLoopInstance.value = null
if (type === "Null") {
modeling.updateProperties(element, { loopCharacteristics: null })
multiInstanceMode.value = "normal"
return
}
// 时序
let newLc
if (type === "SequentialMultiInstance") {
multiLoopInstance.value = modelerStore.moddle.create("bpmn:MultiInstanceLoopCharacteristics", {
newLc = moddle.create("bpmn:MultiInstanceLoopCharacteristics", {
isSequential: true
})
} else {
multiLoopInstance.value = modelerStore.moddle.create("bpmn:MultiInstanceLoopCharacteristics")
newLc = moddle.create("bpmn:MultiInstanceLoopCharacteristics", {
isSequential: false
})
}
modelerStore.modeling.updateProperties(modelerStore.element, {
loopCharacteristics: multiLoopInstance.value
})
modeling.updateProperties(element, { loopCharacteristics: newLc })
}
// 改变多实例模式
const changeMultiInstanceMode = (mode: string) => {
if (!multiLoopInstance.value) return
const handleModeChange = () => {
const element = toRaw(modelerStore.element)
const modeling = getModeling()
let condition = null
if (mode === 'counterSign') {
// 会签: 全部人完成才结束
condition = modelerStore.moddle.create("bpmn:FormalExpression", {
body: '${nrOfCompletedInstances >= nrOfInstances}'
})
} else if (mode === 'orSign') {
// 或签: 任一人完成就结束
condition = modelerStore.moddle.create("bpmn:FormalExpression", {
body: '${nrOfActiveInstances == 0}'
})
console.log('[multiInstance] handleModeChange, multiInstanceMode:', multiInstanceMode.value)
console.log('[multiInstance] element:', element?.id)
console.log('[multiInstance] modeling:', modeling)
if (!modeling || !element) {
console.error('[multiInstance] modeling or element is null')
return
}
modelerStore.modeling.updateModdleProperties(modelerStore.element, multiLoopInstance.value, {
completionCondition: condition
})
if (!element.businessObject?.loopCharacteristics) {
console.log('[multiInstance] no loopCharacteristics, creating new')
handleLoopTypeChange("ParallelMultiInstance")
return
}
const newLc = createLoopCharacteristics()
console.log('[multiInstance] newLc:', newLc)
if (newLc) {
modeling.updateProperties(element, { loopCharacteristics: newLc })
console.log('[multiInstance] updated loopCharacteristics')
}
}
// 循环基数
const updateLoopCardinality = (cardinality: string) => {
let loopCardinality = null
if (cardinality && cardinality.length) {
loopCardinality = modelerStore.moddle.create("bpmn:FormalExpression", { body: cardinality })
const updateLoopCardinality = () => {
const element = toRaw(modelerStore.element)
const modeling = getModeling()
if (!modeling || !element) return
if (!element.businessObject?.loopCharacteristics) return
const newLc = createLoopCharacteristics()
if (newLc) {
modeling.updateProperties(element, { loopCharacteristics: newLc })
}
modelerStore.modeling.updateModdleProperties(modelerStore.element, multiLoopInstance.value, {
loopCardinality
})
}
// 完成条件
const updateLoopCondition = (condition: string) => {
let completionCondition = null
if (condition && condition.length) {
completionCondition = modelerStore.moddle.create("bpmn:FormalExpression", { body: condition })
const updateLoopBase = () => {
const element = toRaw(modelerStore.element)
const modeling = getModeling()
if (!modeling || !element) return
if (!element.businessObject?.loopCharacteristics) return
const newLc = createLoopCharacteristics()
if (newLc) {
modeling.updateProperties(element, { loopCharacteristics: newLc })
}
modelerStore.modeling.updateModdleProperties(modelerStore.element, multiLoopInstance.value, {
completionCondition
})
}
// 重试周期
const updateLoopTimeCycle = (timeCycle: string) => {
const extensionElements = modelerStore.moddle.create("bpmn:ExtensionElements", {
const updateLoopCondition = () => {
const element = toRaw(modelerStore.element)
const modeling = getModeling()
if (!modeling || !element) return
if (!element.businessObject?.loopCharacteristics) return
const newLc = createLoopCharacteristics()
if (newLc) {
modeling.updateProperties(element, { loopCharacteristics: newLc })
}
}
const updateLoopAsync = (type: string) => {
const element = toRaw(modelerStore.element)
const modeling = getModeling()
if (!modeling || !element) return
if (!element.businessObject?.loopCharacteristics) return
const newLc = createLoopCharacteristics()
if (newLc) {
modeling.updateProperties(element, { loopCharacteristics: newLc })
}
}
const updateLoopTimeCycle = () => {
const element = toRaw(modelerStore.element)
const modeling = getModeling()
const moddle = getModdle()
if (!modeling || !element || !moddle) return
if (!element.businessObject?.loopCharacteristics) return
const extElements = moddle.create("bpmn:ExtensionElements", {
values: [
modelerStore.moddle.create(`flowable:FailedJobRetryTimeCycle`, {
body: timeCycle
moddle.create("flowable:FailedJobRetryTimeCycle", {
body: loopInstanceForm.timeCycle
})
]
})
modelerStore.modeling.updateModdleProperties(modelerStore.element, multiLoopInstance.value, {
extensionElements
})
}
// 直接更新的基础信息
const updateLoopBase = () => {
modelerStore.modeling.updateModdleProperties(modelerStore.element, multiLoopInstance.value, {
collection: loopInstanceForm.collection || null,
elementVariable: loopInstanceForm.elementVariable || null
})
const newLc = createLoopCharacteristics({ extensionElements: extElements })
if (newLc) {
modeling.updateProperties(element, { loopCharacteristics: newLc })
}
}
// 各异步状态
const updateLoopAsync = (key: string) => {
const { asyncBefore, asyncAfter } = loopInstanceForm
let asyncAttr: Record<string, any> = {}
onMounted(() => {
if (props.id) {
loadElementData()
}
})
if (!asyncBefore && !asyncAfter) {
loopInstanceForm.exclusive = false
asyncAttr = { asyncBefore: false, asyncAfter: false, exclusive: false, extensionElements: null }
} else {
asyncAttr[key] = loopInstanceForm[key]
watch(() => props.id, (newId) => {
if (newId) {
loadElementData()
}
})
modelerStore.modeling.updateModdleProperties(modelerStore.element, multiLoopInstance.value, asyncAttr)
}
watch(() => modelerStore.element, () => {
if (props.id) {
loadElementData()
}
})
</script>
<style lang="scss">
.panel-tab__content {
.ant-checkbox-wrapper {
margin-right: 8px;
.ant-radio-group {
width: 100%;
}
}
</style>
\ No newline at end of file
......@@ -6,7 +6,6 @@
@sendWorkFlow="handleDefinitionSend"
@endWorkFlow="handleDefinitionEnd"
@open-multi-form="handleOpenMultiForm"
@open-flow-form="handleOpenFlowForm"
:todo-list="todoList"
/>
<WorkFlowFormDrawer
......@@ -152,6 +151,7 @@
if (!data.procInsId) {
await handleDefinitionStart(data)
}
await setCurrentNodeById(data);
dataId.value = data.id;
deployId.value = currentNode.value.deployId || '';
......@@ -210,7 +210,9 @@
}
};
const handleDrawerClose = () => { drawerVisible.value = false; };
const handleDrawerClose = () => {
drawerVisible.value = false;
};
const handleMultiFormDataUpdate = (_data: any) => {
const currentFormComponent = getCurrentFormComponent();
if (currentFormComponent?.handleRefresh) {
......@@ -245,6 +247,7 @@
}
async function handleOpenMultiForm(data: any) {
deployId.value = currentNode.value.deployId || '';
procInsId.value = data.procInsId || '';
drawerVisible.value = true;
......@@ -267,9 +270,7 @@
nextTick(() => {
if(resData.formUrl) {
mainFormUrl.value = resData.formUrl
alert(mainFormUrl.value)
mainFormListUrl.value = resData.formListurl || ''
alert(mainFormListUrl.value)
} else {
mainFormUrl.value = ""
refInnerForm.value.iniData(resData)
......@@ -288,6 +289,15 @@
startTime: undefined,
});
const setCurrentNodeById = async (nodeId: string) =>{
const nodes = workflowNodes.value;
const index = nodes.findIndex(node => node.id === nodeId);
if (index !== -1) {
currentMultiFormIndex.value = index;
currentNode.value = nodes[index];
}
}
onMounted(async () => {
await nextTick();
......
......@@ -35,7 +35,7 @@
import BaosongAllocDrawer from '../form/BaosongAllocDrawer.vue';
const [registerModal, { openModal }] = useModal();
const refAllocDrawer = ref<InstanceType<typeof BaosongAllocDrawer>>();
const refAllocDrawer = ref();
const { tableContext } = useListPage({
tableProps: {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论