仿钉钉设计流程:增加包容分支

This commit is contained in:
jason 2024-04-07 22:31:56 +08:00
parent 32d2eb11f0
commit 11b7cf32ca
4 changed files with 125 additions and 30 deletions

View File

@ -42,6 +42,12 @@
</div> </div>
<p>并行分支</p> <p>并行分支</p>
</a> </a>
<a class="add-node-popover-item condition" @click="addType(7)">
<div class="item-wrapper">
<span class="iconfont icon-Inclusive"></span>
</div>
<p>包容分支</p>
</a>
</div> </div>
<template #reference> <template #reference>
<button class="btn" type="button" v-if="showAddButton"> <button class="btn" type="button" v-if="showAddButton">
@ -110,7 +116,7 @@ const addType = (type: number) => {
childNode: props.childNodeP, childNode: props.childNodeP,
conditionNodes: [ conditionNodes: [
{ {
name: '条件1', name: '分支1',
error: true, error: true,
type: 3, type: 3,
priorityLevel: 1, priorityLevel: 1,
@ -157,6 +163,35 @@ const addType = (type: number) => {
} }
emits('update:childNodeP', data) emits('update:childNodeP', data)
} }
// fork
if (type === NodeType.INCLUSIVE_NODE_FORK) {
const data = {
name: '包容分支_FORK',
type: 7,
id: 'GateWay_' + generateUUID(),
conditionNodes: [
{
name: '分支1',
error: true,
type: 3,
childNode: null
},
{
name: '其它情况',
type: 3,
childNode: null
}
],
childNode: {
id: 'GateWay_' + generateUUID(),
name: '包容分支_JOIN',
type: 8,
error: true,
childNode: props.childNodeP,
}
}
emits('update:childNodeP', data)
}
// if (type != 4) { // if (type != 4) {
// var data // var data
// if (type == 1) { // if (type == 1) {

View File

@ -28,7 +28,15 @@ export enum NodeType {
/** /**
* *
*/ */
PARALLEL_NODE_JOIN = 6 PARALLEL_NODE_JOIN = 6,
/**
*
*/
INCLUSIVE_NODE_FORK = 7,
/**
*
*/
INCLUSIVE_NODE_JOIN = 8
} }
export const NODE_BG_COLOR = new Map() export const NODE_BG_COLOR = new Map()
@ -48,8 +56,8 @@ export type WorkFlowNode = {
id: string, id: string,
type: NodeType, type: NodeType,
name: string, name: string,
attributes: Object | undefined, attributes: any,
// 操作人 // 操作人
childNode?: WorkFlowNode | undefined, childNode?: WorkFlowNode | undefined,
conditionNodes: WorkFlowNode[] | undefined conditionNodes: WorkFlowNode[]
} }

View File

@ -71,8 +71,8 @@
> --> > -->
<i <i
class="anticon anticon-close close" class="anticon anticon-close close"
@click="delTerm(index)" @click="delTerm(nodeConfig.type,index)"
v-if="index != nodeConfig.conditionNodes?.length - 1" v-if="nodeConfig.conditionNodes && index != nodeConfig.conditionNodes?.length - 1"
></i> ></i>
</div> </div>
<div class="auto-judge" :class="isTried && item.error ? 'error active' : ''"> <div class="auto-judge" :class="isTried && item.error ? 'error active' : ''">
@ -145,6 +145,55 @@
<div class="top-left-cover-line"></div> <div class="top-left-cover-line"></div>
<div class="bottom-left-cover-line"></div> <div class="bottom-left-cover-line"></div>
</template> </template>
<template v-if="index === nodeConfig.conditionNodes.length - 1">
<div class="top-right-cover-line"></div>
<div class="bottom-right-cover-line"></div>
</template>
</div>
</div>
<addNode v-model:childNodeP="nodeConfig.childNode" :show-add-button="false" />
</div>
</div>
<div class="branch-wrap" v-if="nodeConfig.type == 7">
<div class="branch-box-wrap">
<div class="branch-box">
<button class="add-branch" @click="addTerm(nodeConfig.type)">添加分支</button>
<div class="col-box" v-for="(item, index) in nodeConfig.conditionNodes" :key="index">
<div class="condition-node">
<div class="condition-node-box">
<div class="title-wrapper" :style="`background: rgb(${bgColors[nodeConfig.type]});`">
<input
v-if="isInputList[index]"
type="text"
class="ant-input editable-title-input"
@blur="blurEvent(index)"
@focus="$event.currentTarget?.select()"
v-mountedFoucs
v-model="item.name"
/>
<span v-else class="editable-title" @click="clickEvent(index)">
{{ item.name }}
</span>
<i
class="anticon anticon-close close"
@click="delTerm(nodeConfig.type,index)"
v-if="index != nodeConfig.conditionNodes?.length - 1"
></i>
</div>
<div class="auto-judge" :class="isTried && item.error ? 'error active' : ''">
<div class="content">{{ conditionStr(nodeConfig, index) }}</div>
<div class="error_tip" v-if="isTried && item.error">
<i class="anticon anticon-exclamation-circle"></i>
</div>
</div>
<addNode v-model:childNodeP="item.childNode" />
</div>
</div>
<nodeWrap v-if="item.childNode" v-model:nodeConfig="item.childNode" />
<template v-if="index == 0">
<div class="top-left-cover-line"></div>
<div class="bottom-left-cover-line"></div>
</template>
<template v-if="index == nodeConfig.conditionNodes.length - 1"> <template v-if="index == nodeConfig.conditionNodes.length - 1">
<div class="top-right-cover-line"></div> <div class="top-right-cover-line"></div>
<div class="bottom-right-cover-line"></div> <div class="bottom-right-cover-line"></div>
@ -154,7 +203,7 @@
<addNode v-model:childNodeP="nodeConfig.childNode" :show-add-button="false" /> <addNode v-model:childNodeP="nodeConfig.childNode" :show-add-button="false" />
</div> </div>
</div> </div>
<div class="node-wrap" v-if="nodeConfig.type === 6"> <div class="node-wrap" v-if="nodeConfig.type === NodeType.PARALLEL_NODE_JOIN || nodeConfig.type === NodeType.INCLUSIVE_NODE_JOIN">
<div class="node-wrap-box"> <div class="node-wrap-box">
<div class="content"> <div class="content">
<div class="text">聚合</div> <div class="text">聚合</div>
@ -178,7 +227,7 @@ import {
import { WorkFlowNode, NodeType } from './consts' import { WorkFlowNode, NodeType } from './consts'
import { useWorkFlowStoreWithOut } from '@/store/modules/simpleWorkflow' import { useWorkFlowStoreWithOut } from '@/store/modules/simpleWorkflow'
let _uid = getCurrentInstance().uid let _uid = getCurrentInstance().uid
import { generateUUID } from '@/utils'
let props = defineProps({ let props = defineProps({
nodeConfig: { nodeConfig: {
type: Object as () => WorkFlowNode, type: Object as () => WorkFlowNode,
@ -293,18 +342,21 @@ const delNode = () => {
const addTerm = (type:number) => { const addTerm = (type:number) => {
const len = props.nodeConfig.conditionNodes.length const len = props.nodeConfig.conditionNodes.length
let lastIndex = props.nodeConfig.conditionNodes.length - 1 let lastIndex = props.nodeConfig.conditionNodes.length - 1
let nodeName = '条件' + len let nodeName = '分支' + len
if(type === NodeType.PARALLEL_NODE_FORK) { if(type === NodeType.PARALLEL_NODE_FORK) {
nodeName = '并行' + (len+1); nodeName = '并行' + (len+1);
lastIndex = props.nodeConfig.conditionNodes.length; lastIndex = props.nodeConfig.conditionNodes.length;
} }
// eslint-disable-next-line vue/no-mutating-props const conditionData = {
props.nodeConfig.conditionNodes.splice(lastIndex, 0, { id: 'SequenceFlow'+ generateUUID(),
name: nodeName, name: nodeName,
type: 3, type: NodeType.CONDITION_NODE,
conditionList: [], childNode: undefined,
childNode: null conditionNodes:[],
}) attributes : undefined
};
// eslint-disable-next-line vue/no-mutating-props
props.nodeConfig.conditionNodes.splice(lastIndex, 0, conditionData)
resetConditionNodesErr() resetConditionNodesErr()
emits('update:nodeConfig', props.nodeConfig) emits('update:nodeConfig', props.nodeConfig)
} }
@ -320,7 +372,7 @@ const delTerm = (nodeType: number, index: number) => {
props.nodeConfig.conditionNodes.map((item, index) => { props.nodeConfig.conditionNodes.map((item, index) => {
// item.priorityLevel = index + 1 // item.priorityLevel = index + 1
if (index !== props.nodeConfig.conditionNodes.length - 1) { if (index !== props.nodeConfig.conditionNodes.length - 1) {
item.name = `条件${index + 1}` item.name = `分支${index + 1}`
} }
}) })
} }
@ -328,7 +380,7 @@ const delTerm = (nodeType: number, index: number) => {
resetConditionNodesErr() resetConditionNodesErr()
emits('update:nodeConfig', props.nodeConfig) emits('update:nodeConfig', props.nodeConfig)
if (props.nodeConfig.conditionNodes.length == 1) { if (props.nodeConfig.conditionNodes.length == 1) {
if (nodeType === NodeType.PARALLEL_NODE_FORK) { if (nodeType === NodeType.PARALLEL_NODE_FORK || nodeType === NodeType.INCLUSIVE_NODE_FORK) {
const joinNode = props.nodeConfig.childNode; const joinNode = props.nodeConfig.childNode;
if (joinNode?.childNode) { if (joinNode?.childNode) {
if (props.nodeConfig.conditionNodes[0].childNode) { if (props.nodeConfig.conditionNodes[0].childNode) {

View File

@ -164,18 +164,18 @@ export const conditionStr = (nodeConfig, index) => {
// } // }
} }
export const dealStr = (str: string, obj) => { // export const dealStr = (str: string, obj) => {
const arr = [] // const arr = []
const list = str.split(',') // const list = str.split(',')
for (const elem in obj) { // for (const elem in obj) {
list.map((item) => { // list.map((item) => {
if (item == elem) { // if (item == elem) {
arr.push(obj[elem].value) // arr.push(obj[elem].value)
} // }
}) // })
} // }
return arr.join('或') // return arr.join('或')
} // }
export const removeEle = (arr, elem, key = 'id') => { export const removeEle = (arr, elem, key = 'id') => {
let includesIndex let includesIndex
@ -187,7 +187,7 @@ export const removeEle = (arr, elem, key = 'id') => {
arr.splice(includesIndex, 1) arr.splice(includesIndex, 1)
} }
export const bgColors = ['87, 106, 149', '255, 148, 62', '50, 150, 250','50, 150, 250','248, 107, 248','244, 118, 118'] export const bgColors = ['87, 106, 149', '255, 148, 62', '50, 150, 250','50, 150, 250','248, 107, 248','244, 118, 118','23, 148, 46','23, 148, 46']
export const placeholderList = ['发起人', '审核人', '抄送人'] export const placeholderList = ['发起人', '审核人', '抄送人']
export const setTypes = [ export const setTypes = [
{ value: 1, label: '指定成员' }, { value: 1, label: '指定成员' },