mirror of
https://gitee.com/myxzgzs/boyue-ui-admin-vue3
synced 2025-08-08 16:32:43 +08:00
feat: 子流程
This commit is contained in:
parent
b2ddefe4a0
commit
357955ce24
1
src/assets/svgs/bpm/async-child-process.svg
Normal file
1
src/assets/svgs/bpm/async-child-process.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1740116978908" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1356" width="200" height="200"><path d="M860.544 633.856c-82.368 0-152.128 69.632-158.464 152h-354.88c-31.616 0-63.296-31.68-63.296-63.296V437.376c12.608 0 25.344 6.4 44.288 6.4h380.16c12.672 69.696 76.032 126.656 152.128 126.656 88.704 0 158.336-69.696 158.336-158.4s-69.632-158.4-158.336-158.4c-76.096 0-139.456 57.024-152.128 126.656h-361.216c-31.616 0-63.296-31.68-63.296-63.296v-133.12h164.736c31.68 0 63.296-22.848 63.296-54.528a55.04 55.04 0 0 0-56-56h-380.16c-31.68 0-70.72 17.984-70.72 56s31.68 54.528 63.36 54.528h133.056v538.624c0 69.696 57.088 126.656 126.72 126.656h386.56c25.344 57.088 82.368 101.376 145.728 101.376a156.8 156.8 0 0 0 158.336-158.4 156.608 156.608 0 0 0-158.208-158.272z m0-316.8c50.624 0 94.912 44.288 94.912 94.976s-44.288 94.976-94.912 94.976c-50.752 0-95.104-44.288-95.104-94.976s44.352-94.976 95.104-94.976z m0 570.24c-50.752 0-95.104-44.352-95.104-95.04s44.352-95.04 95.104-95.04c50.624 0 94.912 44.352 94.912 95.04s-44.288 95.04-94.912 95.04z" p-id="1357" fill="#ffffff"></path></svg>
|
After Width: | Height: | Size: 1.1 KiB |
1
src/assets/svgs/bpm/child-process.svg
Normal file
1
src/assets/svgs/bpm/child-process.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg t="1740116949537" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1153" width="200" height="200"><path d="M440.32 296.96h283.30496v145.92h66.56V230.4H440.32V17.92H17.92v424.96H440.32V296.96zM373.76 376.32H84.48v-291.84H373.76v291.84zM586.24 588.8v143.36512H298.66496V586.24h-66.56v212.48512H586.24V1013.76H1008.64v-424.96h-422.4z m355.84 358.4h-289.28v-291.84H942.08v291.84z" p-id="1154" fill="#ffffff"></path></svg>
|
After Width: | Height: | Size: 465 B |
@ -63,6 +63,18 @@
|
||||
</div>
|
||||
<div class="handler-item-text">触发器</div>
|
||||
</div>
|
||||
<div class="handler-item" @click="addNode(NodeType.CHILD_PROCESS_NODE)">
|
||||
<div class="handler-item-icon child-process">
|
||||
<span class="iconfont icon-size icon-child-process"></span>
|
||||
</div>
|
||||
<div class="handler-item-text">子流程</div>
|
||||
</div>
|
||||
<div class="handler-item" @click="addNode(NodeType.ASYNC_CHILD_PROCESS_NODE)">
|
||||
<div class="handler-item-icon async-child-process">
|
||||
<span class="iconfont icon-size icon-async-child-process"></span>
|
||||
</div>
|
||||
<div class="handler-item-text">异步子流程</div>
|
||||
</div>
|
||||
</div>
|
||||
<template #reference>
|
||||
<div class="add-icon"><Icon icon="ep:plus" /></div>
|
||||
@ -283,6 +295,25 @@ const addNode = (type: number) => {
|
||||
}
|
||||
emits('update:childNode', data)
|
||||
}
|
||||
if (type === NodeType.CHILD_PROCESS_NODE) {
|
||||
const data: SimpleFlowNode = {
|
||||
id: 'Activity_' + generateUUID(),
|
||||
name: NODE_DEFAULT_NAME.get(NodeType.CHILD_PROCESS_NODE) as string,
|
||||
showText: '',
|
||||
type: NodeType.CHILD_PROCESS_NODE,
|
||||
childNode: props.childNode,
|
||||
childProcessSetting: {
|
||||
calledElement: '',
|
||||
calledElementName: '',
|
||||
async: false,
|
||||
skipStartUserNode: false,
|
||||
startUserSetting: {
|
||||
type: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
emits('update:childNode', data)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -54,12 +54,18 @@
|
||||
:flow-node="currentNode"
|
||||
@update:flow-node="handleModelValueUpdate"
|
||||
/>
|
||||
<!-- 触发器节点 -->
|
||||
<TriggerNode
|
||||
<!-- 触发器节点 -->
|
||||
<TriggerNode
|
||||
v-if="currentNode && currentNode.type === NodeType.TRIGGER_NODE"
|
||||
:flow-node="currentNode"
|
||||
@update:flow-node="handleModelValueUpdate"
|
||||
/>
|
||||
<!-- 子流程节点 -->
|
||||
<ChildProcessNode
|
||||
v-if="currentNode && currentNode.type === NodeType.CHILD_PROCESS_NODE"
|
||||
:flow-node="currentNode"
|
||||
@update:flow-node="handleModelValueUpdate"
|
||||
/>
|
||||
<!-- 递归显示孩子节点 -->
|
||||
<ProcessNodeTree
|
||||
v-if="currentNode && currentNode.childNode"
|
||||
@ -85,6 +91,7 @@ import InclusiveNode from './nodes/InclusiveNode.vue'
|
||||
import DelayTimerNode from './nodes/DelayTimerNode.vue'
|
||||
import RouterNode from './nodes/RouterNode.vue'
|
||||
import TriggerNode from './nodes/TriggerNode.vue'
|
||||
import ChildProcessNode from './nodes/ChildProcessNode.vue'
|
||||
import { SimpleFlowNode, NodeType } from './consts'
|
||||
import { useWatchNode } from './node'
|
||||
defineOptions({
|
||||
|
@ -38,6 +38,16 @@ export enum NodeType {
|
||||
*/
|
||||
TRIGGER_NODE = 15,
|
||||
|
||||
/**
|
||||
* 触发器节点
|
||||
*/
|
||||
CHILD_PROCESS_NODE = 20,
|
||||
|
||||
/**
|
||||
* 触发器节点
|
||||
*/
|
||||
ASYNC_CHILD_PROCESS_NODE = 21,
|
||||
|
||||
/**
|
||||
* 条件节点
|
||||
*/
|
||||
@ -128,6 +138,8 @@ export interface SimpleFlowNode {
|
||||
reasonRequire?: boolean
|
||||
// 触发器设置
|
||||
triggerSetting?: TriggerSetting
|
||||
// 子流程
|
||||
childProcessSetting?: ChildProcessSetting
|
||||
}
|
||||
// 候选人策略枚举 ( 用于审批节点。抄送节点 )
|
||||
export enum CandidateStrategy {
|
||||
@ -512,6 +524,7 @@ NODE_DEFAULT_TEXT.set(NodeType.DELAY_TIMER_NODE, '请设置延迟器')
|
||||
NODE_DEFAULT_TEXT.set(NodeType.ROUTER_BRANCH_NODE, '请设置路由节点')
|
||||
NODE_DEFAULT_TEXT.set(NodeType.TRIGGER_NODE, '请设置触发器')
|
||||
NODE_DEFAULT_TEXT.set(NodeType.TRANSACTOR_NODE, '请设置办理人')
|
||||
NODE_DEFAULT_TEXT.set(NodeType.CHILD_PROCESS_NODE, '请设置子流程')
|
||||
|
||||
export const NODE_DEFAULT_NAME = new Map<number, string>()
|
||||
NODE_DEFAULT_NAME.set(NodeType.USER_TASK_NODE, '审批人')
|
||||
@ -522,6 +535,7 @@ NODE_DEFAULT_NAME.set(NodeType.DELAY_TIMER_NODE, '延迟器')
|
||||
NODE_DEFAULT_NAME.set(NodeType.ROUTER_BRANCH_NODE, '路由分支')
|
||||
NODE_DEFAULT_NAME.set(NodeType.TRIGGER_NODE, '触发器')
|
||||
NODE_DEFAULT_NAME.set(NodeType.TRANSACTOR_NODE, '办理人')
|
||||
NODE_DEFAULT_NAME.set(NodeType.CHILD_PROCESS_NODE, '子流程')
|
||||
|
||||
// 候选人策略。暂时不从字典中取。 后续可能调整。控制显示顺序
|
||||
export const CANDIDATE_STRATEGY: DictDataVO[] = [
|
||||
@ -785,3 +799,29 @@ export const TRIGGER_TYPES: DictDataVO[] = [
|
||||
{ label: 'HTTP 请求', value: TriggerTypeEnum.HTTP_REQUEST },
|
||||
{ label: '修改表单数据', value: TriggerTypeEnum.FORM_UPDATE }
|
||||
]
|
||||
|
||||
/**
|
||||
* 子流程节点结构定义
|
||||
*/
|
||||
export type ChildProcessSetting = {
|
||||
calledElement: string
|
||||
calledElementName: string
|
||||
async: boolean,
|
||||
inVariable?: IOParameter[],
|
||||
outVariable?: IOParameter[],
|
||||
skipStartUserNode: boolean,
|
||||
startUserSetting: StartUserSetting,
|
||||
}
|
||||
|
||||
export type IOParameter = {
|
||||
source: string
|
||||
sourceExpression: string
|
||||
target: string
|
||||
targetExpression: string
|
||||
}
|
||||
|
||||
export type StartUserSetting = {
|
||||
type: number
|
||||
formField?: string
|
||||
emptyHandleType?: number
|
||||
}
|
||||
|
@ -0,0 +1,330 @@
|
||||
<template>
|
||||
<el-drawer
|
||||
:append-to-body="true"
|
||||
v-model="settingVisible"
|
||||
:show-close="false"
|
||||
:size="550"
|
||||
:before-close="saveConfig"
|
||||
>
|
||||
<template #header>
|
||||
<div class="config-header">
|
||||
<input
|
||||
v-if="showInput"
|
||||
type="text"
|
||||
class="config-editable-input"
|
||||
@blur="blurEvent()"
|
||||
v-mountedFocus
|
||||
v-model="nodeName"
|
||||
:placeholder="nodeName"
|
||||
/>
|
||||
<div v-else class="node-name">
|
||||
{{ nodeName }} <Icon class="ml-1" icon="ep:edit-pen" :size="16" @click="clickIcon()" />
|
||||
</div>
|
||||
<div class="divide-line"></div>
|
||||
</div>
|
||||
</template>
|
||||
<el-tabs type="border-card" v-model="activeTabName">
|
||||
<el-tab-pane label="子流程" name="child">
|
||||
<div>
|
||||
<el-form ref="formRef" :model="configForm" label-position="top" :rules="formRules">
|
||||
<el-form-item label="选择子流程" prop="calledElement">
|
||||
<el-select
|
||||
v-model="configForm.calledElement"
|
||||
clearable
|
||||
@change="handleCalledElementChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item, index) in childProcessOptions"
|
||||
:key="index"
|
||||
:label="item.name"
|
||||
:value="item.key"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否自动跳过子流程发起节点" prop="skipStartUserNode">
|
||||
<el-switch
|
||||
v-model="configForm.skipStartUserNode"
|
||||
active-text="跳过"
|
||||
inactive-text="不跳过"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="主→子变量传递" prop="inVariable">
|
||||
<div class="flex pt-2" v-for="(item, index) in configForm.inVariable" :key="index">
|
||||
<div class="mr-2">
|
||||
<el-form-item
|
||||
:prop="`inVariable.${index}.source`"
|
||||
:rules="{
|
||||
required: true,
|
||||
message: '变量不能为空',
|
||||
trigger: 'blur'
|
||||
}"
|
||||
>
|
||||
<el-select class="w-200px!" v-model="item.source">
|
||||
<el-option
|
||||
v-for="(field, fIdx) in formFieldOptions"
|
||||
:key="fIdx"
|
||||
:label="field.title"
|
||||
:value="field.field"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="mr-2">
|
||||
<el-form-item
|
||||
:prop="`inVariable.${index}.target`"
|
||||
:rules="{
|
||||
required: true,
|
||||
message: '变量不能为空',
|
||||
trigger: 'blur'
|
||||
}"
|
||||
>
|
||||
<el-select class="w-200px!" v-model="item.target">
|
||||
<el-option
|
||||
v-for="(field, fIdx) in childFormFieldOptions"
|
||||
:key="fIdx"
|
||||
:label="field.title"
|
||||
:value="field.field"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="mr-1 flex items-center">
|
||||
<Icon
|
||||
icon="ep:delete"
|
||||
:size="18"
|
||||
@click="deleteVariable(configForm.inVariable, index)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<el-button type="primary" text @click="addVariable(configForm.inVariable)">
|
||||
<Icon icon="ep:plus" class="mr-5px" />添加一行
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="currentNode.childProcessSetting?.async === false"
|
||||
label="子→主变量传递"
|
||||
prop="outVariable"
|
||||
>
|
||||
<div class="flex pt-2" v-for="(item, index) in configForm.outVariable" :key="index">
|
||||
<div class="mr-2">
|
||||
<el-form-item
|
||||
:prop="`outVariable.${index}.source`"
|
||||
:rules="{
|
||||
required: true,
|
||||
message: '变量不能为空',
|
||||
trigger: 'blur'
|
||||
}"
|
||||
>
|
||||
<el-select class="w-200px!" v-model="item.source">
|
||||
<el-option
|
||||
v-for="(field, fIdx) in childFormFieldOptions"
|
||||
:key="fIdx"
|
||||
:label="field.title"
|
||||
:value="field.field"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="mr-2">
|
||||
<el-form-item
|
||||
:prop="`outVariable.${index}.target`"
|
||||
:rules="{
|
||||
required: true,
|
||||
message: '变量不能为空',
|
||||
trigger: 'blur'
|
||||
}"
|
||||
>
|
||||
<el-select class="w-200px!" v-model="item.target">
|
||||
<el-option
|
||||
v-for="(field, fIdx) in formFieldOptions"
|
||||
:key="fIdx"
|
||||
:label="field.title"
|
||||
:value="field.field"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="mr-1 flex items-center">
|
||||
<Icon
|
||||
icon="ep:delete"
|
||||
:size="18"
|
||||
@click="deleteVariable(configForm.outVariable, index)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<el-button type="primary" text @click="addVariable(configForm.outVariable)">
|
||||
<Icon icon="ep:plus" class="mr-5px" />添加一行
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item label="子流程发起人" prop="startUserType">
|
||||
<el-radio-group v-model="configForm.startUserType">
|
||||
<el-radio :value="1">同主流程发起人</el-radio>
|
||||
<el-radio :value="2">表单</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="configForm.startUserType === 2"
|
||||
label="当子流程发起人为空时"
|
||||
prop="startUserType"
|
||||
>
|
||||
<el-radio-group v-model="configForm.startUserEmptyType">
|
||||
<el-radio :value="1">同主流程发起人</el-radio>
|
||||
<el-radio :value="2">子流程管理员</el-radio>
|
||||
<el-radio :value="3">主流程管理员</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="configForm.startUserType === 2"
|
||||
label="发起人表单"
|
||||
prop="startUserFormField"
|
||||
>
|
||||
<el-select class="w-200px!" v-model="configForm.startUserFormField">
|
||||
<el-option
|
||||
v-for="(field, fIdx) in formFieldOptions"
|
||||
:key="fIdx"
|
||||
:label="field.title"
|
||||
:value="field.field"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<template #footer>
|
||||
<el-divider />
|
||||
<div>
|
||||
<el-button type="primary" @click="saveConfig">确 定</el-button>
|
||||
<el-button @click="closeDrawer">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { getModelList } from '@/api/bpm/model'
|
||||
import { getForm } from '@/api/bpm/form'
|
||||
import { SimpleFlowNode, NodeType } from '../consts'
|
||||
import { useWatchNode, useDrawer, useNodeName, useFormFieldsAndStartUser } from '../node'
|
||||
import { parseFormFields } from '@/components/FormCreate/src/utils'
|
||||
defineOptions({
|
||||
name: 'ChildProcessNodeConfig'
|
||||
})
|
||||
const props = defineProps({
|
||||
flowNode: {
|
||||
type: Object as () => SimpleFlowNode,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
// 抽屉配置
|
||||
const { settingVisible, closeDrawer, openDrawer } = useDrawer()
|
||||
// 当前节点
|
||||
const currentNode = useWatchNode(props)
|
||||
// 节点名称
|
||||
const { nodeName, showInput, clickIcon, blurEvent } = useNodeName(NodeType.CHILD_PROCESS_NODE)
|
||||
// 激活的 Tab 标签页
|
||||
const activeTabName = ref('child')
|
||||
// 子流程表单配置
|
||||
const formRef = ref() // 表单 Ref
|
||||
// 表单校验规则
|
||||
const formRules = reactive({
|
||||
calledElement: [{ required: true, message: '子流程不能为空', trigger: 'change' }],
|
||||
skipStartUserNode: [
|
||||
{ required: true, message: '是否自动跳过子流程发起节点不能为空', trigger: 'change' }
|
||||
],
|
||||
startUserType: [{ required: true, message: '子流程发起人不能为空', trigger: 'change' }],
|
||||
startUserEmptyType: [
|
||||
{ required: true, message: '当子流程发起人为空时不能为空', trigger: 'change' }
|
||||
],
|
||||
startUserFormField: [{ required: true, message: '发起人表单不能为空', trigger: 'change' }]
|
||||
})
|
||||
const configForm = ref({
|
||||
calledElement: '',
|
||||
skipStartUserNode: false,
|
||||
inVariable: [],
|
||||
outVariable: [],
|
||||
startUserType: 1,
|
||||
startUserEmptyType: 1,
|
||||
startUserFormField: ''
|
||||
})
|
||||
const childProcessOptions = ref()
|
||||
const formFieldOptions = useFormFieldsAndStartUser()
|
||||
const childFormFieldOptions = ref()
|
||||
|
||||
// 保存配置
|
||||
const saveConfig = async () => {
|
||||
activeTabName.value = 'child'
|
||||
if (!formRef) return false
|
||||
const valid = await formRef.value.validate()
|
||||
if (!valid) return false
|
||||
const childInfo = childProcessOptions.value.find(
|
||||
(option) => option.key === configForm.value.calledElement
|
||||
)
|
||||
currentNode.value.name = nodeName.value!
|
||||
if (currentNode.value.childProcessSetting) {
|
||||
currentNode.value.childProcessSetting.calledElement = childInfo.key
|
||||
currentNode.value.childProcessSetting.calledElementName = childInfo.name
|
||||
currentNode.value.childProcessSetting.skipStartUserNode = configForm.value.skipStartUserNode
|
||||
currentNode.value.childProcessSetting.inVariable = configForm.value.inVariable
|
||||
currentNode.value.childProcessSetting.outVariable = configForm.value.outVariable
|
||||
currentNode.value.childProcessSetting.startUserSetting.type = configForm.value.startUserType
|
||||
currentNode.value.childProcessSetting.startUserSetting.emptyHandleType =
|
||||
configForm.value.startUserEmptyType
|
||||
currentNode.value.childProcessSetting.startUserSetting.formField =
|
||||
configForm.value.startUserFormField
|
||||
}
|
||||
currentNode.value.showText = `调用子流程:${childInfo.name}`
|
||||
settingVisible.value = false
|
||||
return true
|
||||
}
|
||||
// 显示子流程节点配置, 由父组件传过来
|
||||
const showChildProcessNodeConfig = (node: SimpleFlowNode) => {
|
||||
nodeName.value = node.name
|
||||
if (node.childProcessSetting) {
|
||||
configForm.value.calledElement = node.childProcessSetting.calledElement
|
||||
configForm.value.skipStartUserNode = node.childProcessSetting.skipStartUserNode
|
||||
configForm.value.inVariable = node.childProcessSetting.inVariable
|
||||
configForm.value.outVariable = node.childProcessSetting.outVariable
|
||||
configForm.value.startUserType = node.childProcessSetting.startUserSetting.type
|
||||
configForm.value.startUserEmptyType =
|
||||
node.childProcessSetting.startUserSetting.emptyHandleType ?? 1
|
||||
configForm.value.startUserFormField = node.childProcessSetting.startUserSetting.formField ?? ''
|
||||
}
|
||||
loadFormInfo()
|
||||
}
|
||||
|
||||
defineExpose({ openDrawer, showChildProcessNodeConfig }) // 暴露方法给父组件
|
||||
|
||||
const addVariable = (arr) => {
|
||||
arr.push({
|
||||
source: '',
|
||||
target: ''
|
||||
})
|
||||
}
|
||||
const deleteVariable = (arr, index: number) => {
|
||||
arr.splice(index, 1)
|
||||
}
|
||||
const handleCalledElementChange = () => {
|
||||
configForm.value.inVariable = []
|
||||
configForm.value.outVariable = []
|
||||
loadFormInfo()
|
||||
}
|
||||
const loadFormInfo = async () => {
|
||||
const childInfo = childProcessOptions.value.find(
|
||||
(option) => option.key === configForm.value.calledElement
|
||||
)
|
||||
const formInfo = await getForm(childInfo.formId)
|
||||
childFormFieldOptions.value = []
|
||||
if (formInfo.fields) {
|
||||
formInfo.fields.forEach((fieldStr: string) => {
|
||||
parseFormFields(JSON.parse(fieldStr), childFormFieldOptions.value)
|
||||
})
|
||||
}
|
||||
console.log(childFormFieldOptions.value)
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
childProcessOptions.value = await getModelList(undefined)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
@ -0,0 +1,104 @@
|
||||
<template>
|
||||
<div class="node-wrapper">
|
||||
<div class="node-container">
|
||||
<div
|
||||
class="node-box"
|
||||
:class="[
|
||||
{ 'node-config-error': !currentNode.showText },
|
||||
`${useTaskStatusClass(currentNode?.activityStatus)}`
|
||||
]"
|
||||
>
|
||||
<div class="node-title-container">
|
||||
<div
|
||||
:class="`node-title-icon ${currentNode.childProcessSetting?.async === true ? 'async-child-process' : 'child-process'}`"
|
||||
>
|
||||
<span
|
||||
:class="`iconfont ${currentNode.childProcessSetting?.async === true ? 'icon-async-child-process' : 'icon-child-process'}`"
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
<input
|
||||
v-if="!readonly && showInput"
|
||||
type="text"
|
||||
class="editable-title-input"
|
||||
@blur="blurEvent()"
|
||||
v-mountedFocus
|
||||
v-model="currentNode.name"
|
||||
:placeholder="currentNode.name"
|
||||
/>
|
||||
<div v-else class="node-title" @click="clickTitle">
|
||||
{{ currentNode.name }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="node-content" @click="openNodeConfig">
|
||||
<div class="node-text" :title="currentNode.showText" v-if="currentNode.showText">
|
||||
{{ currentNode.showText }}
|
||||
</div>
|
||||
<div class="node-text" v-else>
|
||||
{{ NODE_DEFAULT_TEXT.get(NodeType.CHILD_PROCESS_NODE) }}
|
||||
</div>
|
||||
<Icon v-if="!readonly" icon="ep:arrow-right-bold" />
|
||||
</div>
|
||||
<div v-if="!readonly" class="node-toolbar">
|
||||
<div class="toolbar-icon"
|
||||
><Icon color="#0089ff" icon="ep:circle-close-filled" :size="18" @click="deleteNode"
|
||||
/></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 传递子节点给添加节点组件。会在子节点前面添加节点 -->
|
||||
<NodeHandler
|
||||
v-if="currentNode"
|
||||
v-model:child-node="currentNode.childNode"
|
||||
:current-node="currentNode"
|
||||
/>
|
||||
</div>
|
||||
<ChildProcessNodeConfig
|
||||
v-if="!readonly && currentNode"
|
||||
ref="nodeSetting"
|
||||
:flow-node="currentNode"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { SimpleFlowNode, NodeType, NODE_DEFAULT_TEXT } from '../consts'
|
||||
import NodeHandler from '../NodeHandler.vue'
|
||||
import { useNodeName2, useWatchNode, useTaskStatusClass } from '../node'
|
||||
import ChildProcessNodeConfig from '../nodes-config/ChildProcessNodeConfig.vue'
|
||||
defineOptions({
|
||||
name: 'ChildProcessNode'
|
||||
})
|
||||
const props = defineProps({
|
||||
flowNode: {
|
||||
type: Object as () => SimpleFlowNode,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
// 定义事件,更新父组件。
|
||||
const emits = defineEmits<{
|
||||
'update:flowNode': [node: SimpleFlowNode | undefined]
|
||||
}>()
|
||||
// 是否只读
|
||||
const readonly = inject<Boolean>('readonly')
|
||||
// 监控节点的变化
|
||||
const currentNode = useWatchNode(props)
|
||||
// 节点名称编辑
|
||||
const { showInput, blurEvent, clickTitle } = useNodeName2(currentNode, NodeType.CHILD_PROCESS_NODE)
|
||||
const nodeSetting = ref()
|
||||
// 打开节点配置
|
||||
const openNodeConfig = () => {
|
||||
if (readonly) {
|
||||
return
|
||||
}
|
||||
nodeSetting.value.showChildProcessNodeConfig(currentNode.value)
|
||||
nodeSetting.value.openDrawer()
|
||||
}
|
||||
|
||||
// 删除节点。更新当前节点为孩子节点
|
||||
const deleteNode = () => {
|
||||
emits('update:flowNode', currentNode.value.childNode)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -181,6 +181,14 @@
|
||||
color: #330099;
|
||||
}
|
||||
|
||||
.child-process {
|
||||
color: #996633;
|
||||
}
|
||||
|
||||
.async-child-process {
|
||||
color: #006666;
|
||||
}
|
||||
|
||||
.handler-item-text {
|
||||
margin-top: 4px;
|
||||
width: 80px;
|
||||
@ -302,6 +310,14 @@
|
||||
&.transactor-task {
|
||||
color: #330099;
|
||||
}
|
||||
|
||||
&.child-process {
|
||||
color: #996633;
|
||||
}
|
||||
|
||||
&.async-child-process {
|
||||
color: #006666;
|
||||
}
|
||||
}
|
||||
|
||||
.node-title {
|
||||
@ -800,3 +816,11 @@
|
||||
.icon-parallel:before {
|
||||
content: "\e688";
|
||||
}
|
||||
|
||||
.icon-async-child-process:before {
|
||||
content: "\e6f2";
|
||||
}
|
||||
|
||||
.icon-child-process:before {
|
||||
content: "\e6c1";
|
||||
}
|
||||
|
@ -157,24 +157,24 @@ const initProcessInfo = async (row: any, formVariables?: any) => {
|
||||
}
|
||||
|
||||
/** 预测流程节点会因为输入的参数值而产生新的预测结果值,所以需重新预测一次 */
|
||||
watch(
|
||||
detailForm.value,
|
||||
(newValue) => {
|
||||
if (newValue && Object.keys(newValue.value).length > 0) {
|
||||
// 记录之前的节点审批人
|
||||
tempStartUserSelectAssignees.value = startUserSelectAssignees.value
|
||||
startUserSelectAssignees.value = {}
|
||||
// 加载最新的审批详情
|
||||
getApprovalDetail({
|
||||
id: props.selectProcessDefinition.id,
|
||||
processVariablesStr: JSON.stringify(newValue.value) // 解决 GET 无法传递对象的问题,后端 String 再转 JSON
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
// watch(
|
||||
// detailForm.value,
|
||||
// (newValue) => {
|
||||
// if (newValue && Object.keys(newValue.value).length > 0) {
|
||||
// // 记录之前的节点审批人
|
||||
// tempStartUserSelectAssignees.value = startUserSelectAssignees.value
|
||||
// startUserSelectAssignees.value = {}
|
||||
// // 加载最新的审批详情
|
||||
// getApprovalDetail({
|
||||
// id: props.selectProcessDefinition.id,
|
||||
// processVariablesStr: JSON.stringify(newValue.value) // 解决 GET 无法传递对象的问题,后端 String 再转 JSON
|
||||
// })
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// immediate: true
|
||||
// }
|
||||
// )
|
||||
|
||||
/** 获取审批详情 */
|
||||
const getApprovalDetail = async (row: any) => {
|
||||
|
@ -85,7 +85,9 @@ const setSimpleModelNodeTaskStatus = (
|
||||
if (
|
||||
simpleModel.type === NodeType.START_USER_NODE ||
|
||||
simpleModel.type === NodeType.USER_TASK_NODE ||
|
||||
simpleModel.type === NodeType.TRANSACTOR_NODE
|
||||
simpleModel.type === NodeType.TRANSACTOR_NODE ||
|
||||
simpleModel.type === NodeType.CHILD_PROCESS_NODE ||
|
||||
simpleModel.type === NodeType.ASYNC_CHILD_PROCESS_NODE
|
||||
) {
|
||||
simpleModel.activityStatus = TaskStatusEnum.NOT_START
|
||||
if (rejectedTaskActivityIds.includes(simpleModel.id)) {
|
||||
|
@ -181,6 +181,8 @@ import conditionSvg from '@/assets/svgs/bpm/condition.svg'
|
||||
import parallelSvg from '@/assets/svgs/bpm/parallel.svg'
|
||||
import finishSvg from '@/assets/svgs/bpm/finish.svg'
|
||||
import transactorSvg from '@/assets/svgs/bpm/transactor.svg'
|
||||
import childProcessSvg from '@/assets/svgs/bpm/child-process.svg'
|
||||
import asyncChildProcessSvg from '@/assets/svgs/bpm/async-child-process.svg'
|
||||
|
||||
defineOptions({ name: 'BpmProcessInstanceTimeline' })
|
||||
withDefaults(
|
||||
@ -249,7 +251,11 @@ const nodeTypeSvgMap = {
|
||||
// 条件分支节点
|
||||
[NodeType.CONDITION_NODE]: { color: '#14bb83', svg: conditionSvg },
|
||||
// 并行分支节点
|
||||
[NodeType.PARALLEL_BRANCH_NODE]: { color: '#14bb83', svg: parallelSvg }
|
||||
[NodeType.PARALLEL_BRANCH_NODE]: { color: '#14bb83', svg: parallelSvg },
|
||||
// 子流程节点
|
||||
[NodeType.CHILD_PROCESS_NODE]: { color: '#14bb83', svg: childProcessSvg },
|
||||
// 异步子流程节点
|
||||
[NodeType.ASYNC_CHILD_PROCESS_NODE]: { color: '#14bb83', svg: asyncChildProcessSvg }
|
||||
}
|
||||
|
||||
// 只有只有状态是 -1、0、1 才展示头像右小角状态小icon
|
||||
@ -269,6 +275,8 @@ const getApprovalNodeIcon = (taskStatus: number, nodeType: NodeType) => {
|
||||
nodeType === NodeType.START_USER_NODE ||
|
||||
nodeType === NodeType.USER_TASK_NODE ||
|
||||
nodeType === NodeType.TRANSACTOR_NODE ||
|
||||
nodeType === NodeType.CHILD_PROCESS_NODE ||
|
||||
nodeType === NodeType.ASYNC_CHILD_PROCESS_NODE ||
|
||||
nodeType === NodeType.END_EVENT_NODE
|
||||
) {
|
||||
return statusIconMap[taskStatus]?.icon
|
||||
|
Loading…
x
Reference in New Issue
Block a user