clay commit : workflow开始解析

This commit is contained in:
clay 2022-12-23 00:57:32 +08:00
parent e08d6e691e
commit dff930eb6f
19 changed files with 16967 additions and 520 deletions

View File

@ -1,7 +1,7 @@
spring:
profiles:
active: pro
active: dev
mybatis:
type-aliases-package: cn.odliken.flow.pojo

File diff suppressed because it is too large Load Diff

View File

@ -39,6 +39,7 @@ import FormBaseSetting from '@/views/admin/layout/FormBaseSetting'
import FormDesign from '@/views/admin/layout/FormDesign'
import ProcessDesign from '@/views/admin/layout/ProcessDesign'
import FormProSetting from '@/views/admin/layout/FormProSetting'
import axios from "axios";
export default {
name: "FormProcessDesign",
@ -60,15 +61,15 @@ export default {
{title: '扩展设置', description: '', icon: '', status: ''}
],
validComponents: ['baseSetting', 'formSetting', 'processDesign', 'proSetting'],
array:[],
array: [],
}
},
computed: {
setup() {
return this.$store.state.design
},
errTitle(){
if (this.validResult.finished && !this.validResult.success){
errTitle() {
if (this.validResult.finished && !this.validResult.success) {
return this.validResult.title + ` (${this.validResult.errs.length}项错误) 😥`
}
return this.validResult.title
@ -131,18 +132,24 @@ export default {
},
groupId: undefined,
formItems: [],
process: {
id: "root",
parentId: null,
type: "ROOT",
name: "发起人",
desc: "任何人",
props: {
assignedUser: [],
formPerms: []
process: [
{
id: "root",
parentId: "admin",
type: "ROOT",
name: "发起人",
desc: "任何人",
props: {
assignedUser: [],
formPerms: []
},
},
children: {}
},
{
id: "end",
parentId: "root",
type: "END",
}
],
remark: "备注说明"
})
},
@ -220,16 +227,15 @@ export default {
}
},
tarry(node){
if (node&&node.id){
tarry(node) {
if (node && node.id) {
let newNode = {...node}
newNode.children=null
newNode.children = null
this.array.push(newNode)
this.tarry(node.children)
}
},
stopTimer() {
if (this.timer) {
@ -239,8 +245,106 @@ export default {
preview() {
this.validateDesign()
},
//
publishProcess() {
this.validateDesign()
this.testPublish()
// this.validateDesign()
},
getToken() {
axios.post(
// "http://localhost:8000/auth/login",
"http://gateway.odliken.cn/auth/login",
{
code: "string",
password: "926425",
username: "admin",
uuid: "string"
}
).then(res => {
console.log(res)
sessionStorage.setItem("token", res.data.data)
this.testPublish()
})
},
testPublish() {
// this.toAjaxAdd()
let token = sessionStorage.getItem("token");
console.log(token)
if (!token) {
this.getToken();
}
let templates = {
formId: this.setup.formId,
formName: this.setup.formName,
logo: this.setup.logo,
settings: this.setup.settings,
groupId: this.setup.groupId,
formItems: this.setup.formItems,
process: this.setup.process,
remark: this.setup.remark
}
console.log(JSON.stringify(templates))
console.log("获取到token")
axios({
method: "post",
url: "http://localhost:8000/workflow/process",
data: this.setup.process,
headers: {
'Content-Type': 'application/json',
"authorization": token
},
}).then(res => {
console.log(res.data)
})
},
toAjaxAdd() {
console.log(this.setup, "数据的哈客户大客户")
let template = {
formId: this.setup.formId,
formName: this.setup.formName,
logo: JSON.stringify(this.setup.logo),
settings: JSON.stringify(this.setup.settings),
groupId: this.setup.groupId,
formItems: JSON.stringify(this.setup.formItems),
process: JSON.stringify(this.setup.process),
remark: this.setup.remark
}
createForm(template).then(rsp => {
this.$message.success("创建表单成功")
this.$router.push("/formsPanel")
}).catch(err => {
this.$message.error(err)
})
},
toAjaxEdit() {
console.log(this.setup)
let template = {
formId: this.setup.formId,
formName: this.setup.formName,
logo: JSON.stringify(this.setup.logo),
settings: JSON.stringify(this.setup.settings),
groupId: this.setup.groupId,
formItems: JSON.stringify(this.setup.formItems),
process: JSON.stringify(this.setup.process),
remark: this.setup.remark
}
console.log(JSON.stringify(template))
updateFormDetail(template).then(rsp => {
this.$message.success("更新表单成功")
this.$router.push("/formsPanel")
}).catch(err => {
this.$message.error(err)
})
},
// todo
doPublish() {
@ -295,10 +399,11 @@ export default {
}
}
.err-info{
.err-info {
max-height: 180px;
overflow-y: auto;
& > div{
& > div {
padding: 5px;
margin: 2px 0;
width: 220px;
@ -306,7 +411,8 @@ export default {
border-radius: 3px;
background: rgb(242 242 242);
}
i{
i {
margin: 0 5px;
}
}

View File

@ -0,0 +1,436 @@
<template>
<el-container>
<el-header style="background: white">
<layout-header v-model="activeSelect" @publish="publishProcess" @preview="preview"></layout-header>
</el-header>
<div class="layout-body">
<form-base-setting ref="baseSetting" v-show="activeSelect === 'baseSetting'"/>
<form-design ref="formSetting" v-show="activeSelect === 'formSetting'"/>
<process-design ref="processDesign" v-show="activeSelect === 'processDesign'"/>
<form-pro-setting ref="proSetting" v-show="activeSelect === 'proSetting'"/>
</div>
<w-dialog :showFooter="false" v-model="validVisible" title="设置项检查">
<el-steps align-center :active="validStep" finish-status="success">
<el-step v-for="(step, i) in validOptions" :title="step.title" :key="i"
:icon="step.icon" :status="step.status" :description="step.description"/>
</el-steps>
<el-result :icon="validIcon" :title="errTitle" :subTitle="validResult.desc">
<i slot="icon" style="font-size: 30px" v-if="!validResult.finished" class="el-icon-loading"></i>
<div slot="subTitle" class="err-info" v-if="validResult.errs.length > 0">
<ellipsis hover-tip v-for="(err, i) in validResult.errs" :key="i + '_err'" :content="err">
<i slot="pre" class="el-icon-warning-outline"></i>
</ellipsis>
</div>
<template slot="extra">
<el-button type="primary" v-if="validResult.finished" size="medium" @click="doAfter">
{{ validResult.action }}
</el-button>
</template>
</el-result>
</w-dialog>
</el-container>
</template>
<script>
import LayoutHeader from './LayoutHeader'
import {getFormDetail, createForm, updateFormDetail} from '@/api/design'
import FormBaseSetting from '@/views/admin/layout/FormBaseSetting'
import FormDesign from '@/views/admin/layout/FormDesign'
import ProcessDesign from '@/views/admin/layout/ProcessDesign'
import FormProSetting from '@/views/admin/layout/FormProSetting'
import axios from "axios";
export default {
name: "FormProcessDesign",
components: {LayoutHeader, FormBaseSetting, FormDesign, ProcessDesign, FormProSetting},
data() {
return {
isNew: true,
validStep: 0,
timer: null,
//todo
// activeSelect: 'baseSetting',
activeSelect: 'processDesign',
validVisible: false,
validResult: {},
validOptions: [
{title: '基础信息', description: '', icon: '', status: ''},
{title: '审批表单', description: '', icon: '', status: ''},
{title: '审批流程', description: '', icon: '', status: ''},
{title: '扩展设置', description: '', icon: '', status: ''}
],
validComponents: ['baseSetting', 'formSetting', 'processDesign', 'proSetting'],
array:[],
}
},
computed: {
setup() {
return this.$store.state.design
},
errTitle(){
if (this.validResult.finished && !this.validResult.success){
return this.validResult.title + ` (${this.validResult.errs.length}项错误) 😥`
}
return this.validResult.title
},
validIcon() {
if (!this.validResult.finished) {
return 'el-icon-loading'
} else if (this.validResult.success) {
return 'success'
} else {
return 'warning'
}
}
},
created() {
this.showValiding()
let formId = this.$route.query.code
//
this.loadInitFrom()
if (this.$isNotEmpty(formId)) {
this.isNew = false
this.loadFormInfo(formId)
}
let group = this.$route.query.group
this.setup.groupId = this.$isNotEmpty(group) ? parseInt(group) : null
},
beforeDestroy() {
this.stopTimer()
},
methods: {
loadFormInfo(formId) {
getFormDetail(formId).then(rsp => {
console.log(rsp.data)
let form = rsp.data;
form.logo = JSON.parse(form.logo)
form.settings = JSON.parse(form.settings)
form.formItems = JSON.parse(form.formItems)
form.process = JSON.parse(form.process)
this.$store.commit('loadForm', form)
}).catch(err => {
this.$message.error(err)
})
},
loadInitFrom() {
this.$store.commit('loadForm', {
formId: null,
formName: "未命名表单",
logo: {
icon: "el-icon-eleme",
background: "#1e90ff"
},
settings: {
commiter: [],
admin: [],
sign: false,
notify: {
types: ["APP"],
title: "消息通知标题"
}
},
groupId: undefined,
formItems: [],
process: {
id: "root",
parentId: "admin",
type: "ROOT",
name: "发起人",
desc: "任何人",
props: {
assignedUser: [],
formPerms: []
},
children: {}
},
// [
// {
// id: "root",
// parentId: "admin",
// type: "ROOT",
// name: "",
// desc: "",
// props: {
// assignedUser: [],
// formPerms: []
// },
// },
// {
// id: "end",
// parentId: "root",
// type: "END",
// name: "",
// desc: "",
// props: {
// assignedUser: [],
// formPerms: []
// },
// }
// ]
remark: "备注说明"
})
},
validateDesign() {
this.validVisible = true
this.validStep = 0
this.showValiding()
this.stopTimer()
this.timer = setInterval(() => {
this.validResult.errs = this.$refs[this.validComponents[this.validStep]].validate()
if (Array.isArray(this.validResult.errs) && this.validResult.errs.length === 0) {
this.validStep++;
if (this.validStep >= this.validOptions.length) {
this.stopTimer()
this.showValidFinish(true)
}
} else {
this.stopTimer()
this.validOptions[this.validStep].status = 'error'
this.showValidFinish(false, this.getDefaultValidErr())
}
}, 300)
},
getDefaultValidErr() {
switch (this.validStep) {
case 0:
return '请检查基础设置项';
case 1:
return '请检查审批表单相关设置'
case 2:
return '请检查审批流程,查看对应标注节点错误信息'
case 3:
return '请检查扩展设置'
default:
return '未知错误'
}
},
showValidFinish(success, err) {
this.validResult.success = success
this.validResult.finished = true
this.validResult.title = success ? '校验完成 😀' : '校验失败 '
this.validResult.desc = success ? '设置项校验成功,是否提交?' : err
this.validResult.action = success ? '提 交' : '去修改'
},
showValiding() {
this.validResult = {
errs: [],
finished: false,
success: false,
title: '检查中...',
action: '处理',
desc: '正在检查设置项'
}
this.validStep = 0
this.validOptions.forEach(op => {
op.status = ''
op.icon = ''
op.description = ''
})
},
doAfter() {
if (this.validResult.success) {
// let process = this.setup.process
// console.log(process)
// this.tarry(process)
//
//
// console.log(this.array)
// this.setup.process = this.array
this.doPublish()
} else {
this.activeSelect = this.validComponents[this.validStep]
this.validVisible = false
}
},
tarry(node){
if (node&&node.id){
let newNode = {...node}
newNode.children=null
this.array.push(newNode)
this.tarry(node.children)
}
},
stopTimer() {
if (this.timer) {
clearInterval(this.timer)
}
},
preview() {
this.validateDesign()
},
//
publishProcess() {
console.log("发布")
this.testPublish()
// this.validateDesign()
},
getToken(){
axios.post(
"http://localhost:8000/auth/login",
{
code: "string",
password: "926425",
username: "admin",
uuid: "string"
}
).then(res =>{
console.log(res)
sessionStorage.setItem("token",res.data.data)
this.testPublish()
})
},
testPublish(){
this.toAjaxAdd();
let token = sessionStorage.getItem("token");
if (!token){
this.getToken();
}
let templates = {
formId: this.setup.formId,
formName: this.setup.formName,
logo: this.setup.logo,
settings: this.setup.settings,
groupId: this.setup.groupId,
formItems: this.setup.formItems,
process: this.setup.process,
remark: this.setup.remark
}
console.log(JSON.stringify(templates))
console.log("获取到token")
// axios.post(
// "",
// templates,
// ).then(res =>{
//
// })
},
toAjaxAdd(){
console.log(this.setup,"数据的哈客户大客户")
let template = {
formId: this.setup.formId,
formName: this.setup.formName,
logo: JSON.stringify(this.setup.logo),
settings: JSON.stringify(this.setup.settings),
groupId: this.setup.groupId,
formItems: JSON.stringify(this.setup.formItems),
process: JSON.stringify(this.setup.process),
remark: this.setup.remark
}
createForm(template).then(rsp => {
this.$message.success("创建表单成功")
this.$router.push("/formsPanel")
}).catch(err => {
this.$message.error(err)
})
},
toAjaxEdit(){
console.log(this.setup)
let template = {
formId: this.setup.formId,
formName: this.setup.formName,
logo: JSON.stringify(this.setup.logo),
settings: JSON.stringify(this.setup.settings),
groupId: this.setup.groupId,
formItems: JSON.stringify(this.setup.formItems),
process: JSON.stringify(this.setup.process),
remark: this.setup.remark
}
console.log(JSON.stringify(template))
updateFormDetail(template).then(rsp => {
this.$message.success("更新表单成功")
this.$router.push("/formsPanel")
}).catch(err => {
this.$message.error(err)
})
},
// todo
doPublish() {
this.$confirm('如果您只想预览请选择预览,确认发布后流程立即生效,是否继续?', '提示', {
confirmButtonText: '发布',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
console.log(this.setup)
let template = {
formId: this.setup.formId,
formName: this.setup.formName,
logo: JSON.stringify(this.setup.logo),
settings: JSON.stringify(this.setup.settings),
groupId: this.setup.groupId,
formItems: JSON.stringify(this.setup.formItems),
process: JSON.stringify(this.setup.process),
remark: this.setup.remark
}
if (this.isNew || !this.$isNotEmpty(this.setup.formId)) {
createForm(template).then(rsp => {
this.$message.success("创建表单成功")
this.$router.push("/formsPanel")
}).catch(err => {
this.$message.error(err)
})
} else {
console.log(JSON.stringify(template))
updateFormDetail(template).then(rsp => {
this.$message.success("更新表单成功")
this.$router.push("/formsPanel")
}).catch(err => {
this.$message.error(err)
})
}
})
}
}
}
</script>
<style lang="less" scoped>
.layout-body {
min-width: 980px;
}
/deep/ .el-step {
.is-success {
color: #2a99ff;
border-color: #2a99ff;
}
}
.err-info{
max-height: 180px;
overflow-y: auto;
& > div{
padding: 5px;
margin: 2px 0;
width: 220px;
text-align: left;
border-radius: 3px;
background: rgb(242 242 242);
}
i{
margin: 0 5px;
}
}
::-webkit-scrollbar {
width: 2px;
height: 2px;
background-color: white;
}
::-webkit-scrollbar-thumb {
border-radius: 16px;
background-color: #e8e8e8;
}
</style>

View File

@ -72,6 +72,11 @@ export default {
}
}
</script>
<style>
::-webkit-scrollbar {
height: 10px !important;
}
</style>
<style lang="less" scoped>
.design {

View File

@ -0,0 +1,696 @@
<script>
//
import Approval from '@/views/common/process/nodes/ApprovalNode.vue'
import Cc from '@/views/common/process/nodes/CcNode.vue'
import Concurrent from '@/views/common/process/nodes/ConcurrentNode.vue'
import Condition from '@/views/common/process/nodes/ConditionNode.vue'
import Trigger from '@/views/common/process/nodes/TriggerNode.vue'
import Delay from '@/views/common/process/nodes/DelayNode.vue'
import Empty from '@/views/common/process/nodes/EmptyNode.vue'
import Merge from '@/views/common/process/nodes/MergeNode.vue'
import Root from '@/views/common/process/nodes/RootNode.vue'
import End from '@/views/common/process/nodes/ProcessEndNode.vue'
import Node from '@/views/common/process/nodes/Node.vue'
import DefaultProps from "./DefaultNodeProps"
export default {
name: "ProcessTree",
components: {Node, Root, Approval, Cc, Trigger, Concurrent, Condition, Delay, Empty,Merge,End},
data() {
return {
valid: true
}
},
computed: {
nodeMap() {
return this.$store.state.nodeMap;
},
parentMap() {
return this.$store.state.parentMap;
},
dom() {
return this.$store.state.design.process;
}
},
// eslint-disable-next-line no-unused-vars
render(h, ctx) {
this.nodeMap.clear()
this.parentMap.clear()
this.initMapping(this.dom)
let processTrees = this.getDomTree(h, "admin")
let endNode = {
id : this.getRandomId(),
type: "End"
}
this.decodeAppendEndDom(h,endNode,processTrees)
//
// processTrees.push(h('div', {style: {'text-align': 'center'}}, [
// h('div', {class: {'process-end': true}, domProps: {innerHTML: ''}})
// ]))
return h('div', {class: {'process-end': true}, ref: 'end'}, processTrees)
},
methods: {
// demo
getDomTree(h, id) {
let node = this.parentMap.get(id)
if (!(node && node.id)) {
return []
}
if (this.isPrimaryNode(node)) {
//
let childDoms = this.getDomTree(h, node.id)
this.decodeAppendDom(h, node, childDoms)
return [h('div', {'class': {'primary-node': true}}, childDoms)];
} else if (this.isBranchNode(node)) {
let index = 0;
//
let branchItems = node.branchs.map(branchNode => {
//
this.toMapping(branchNode)
let childDoms = this.getDomTree(h, branchNode.id)
this.decodeAppendDom(h, branchNode, childDoms, {level: index + 1, size: node.branchs.length})
//4线线
this.insertCoverLine(h, index, childDoms, node.branchs)
//
index++;
return h('div', {'class': {'branch-node-item': true}}, childDoms);
})
///
branchItems.unshift(h('div', {'class': {'add-branch-btn': true}}, [
h('el-button', {
'class': {'add-branch-btn-el': true},
props: {size: 'small', round: true},
on: {click: () => this.addBranchNode(node)},
domProps: {innerHTML: `添加${this.isConditionNodes(node) ? '条件' : '分支'}`},
}, [])
]));
let bchDom = [h('div', {'class': {'branch-node': true}}, branchItems)]
//
let afterChildDoms = this.getDomTree(h, node.id)
return [h('div', {}, [bchDom, afterChildDoms])]
} else if (this.isMergeNode(node)){
//
let childDoms = this.getDomTree(h, node.id)
this.decodeAppendDom(h, node, childDoms)
return [h('div', {'class': {'empty-node': true}}, childDoms)];
} else if (this.isEmptyNode(node)) {
//
let childDoms = this.getDomTree(h, node.id)
this.decodeAppendDom(h, node, childDoms)
return [h('div', {'class': {'empty-node': true}}, childDoms)];
}
return []
},
//dom
decodeAppendDom(h, node, dom, props = {}) {
props.config = node
dom.unshift(h(node.type.toLowerCase(), {
props: props,
ref: node.id,
key: node.id,
///
on: {
insertNode: type => this.insertNode(type, node),
delNode: () => this.delNode(node),
selected: () => this.selectNode(node),
copy: () => this.copyBranch(node),
leftMove: () => this.branchMove(node, -1),
rightMove: () => this.branchMove(node, 1)
}
}, []))
},
decodeAppendEndDom(h, node, dom, props = {}) {
props.config = node
dom.unshift(h(node.type.toLowerCase(), {
props: props,
ref: node.id,
key: node.id,
///
// on: {
// insertNode: type => this.insertNode(type, node),
// delNode: () => this.delNode(node),
// selected: () => this.selectNode(node),
// copy: () => this.copyBranch(node),
// leftMove: () => this.branchMove(node, -1),
// rightMove: () => this.branchMove(node, 1)
// }
}, []))
},
// map,便
initMapping(node) {
console.log(node)
let type = typeof node;
// if (node typeof list){
//
// }
console.log(type)
// if (type == 'object'){
// this.nodeMap.set(node.id, node)
// this.parentMap.set(node.parentId, node)
//
// console.log(node,"'object'")
// }else {
//
// console.log(node,"!object'")
// console.log(node)
console.log(node,"nodeItem")
node.forEach(nodeItem => {
this.nodeMap.set(nodeItem.id, nodeItem)
this.parentMap.set(nodeItem.parentId, nodeItem)
})
// }
},
//idmap
toMapping(node) {
if (node && node.id) {
let newNode = {
...node
}
newNode.children = []
this.nodeMap.set(newNode.id, newNode)
}
},
// 线
insertCoverLine(h, index, doms, branchs) {
if (index === 0) {
//
doms.unshift(h('div', {'class': {'line-top-left': true}}, []))
doms.unshift(h('div', {'class': {'line-bot-left': true}}, []))
}
if (index === branchs.length - 1) {
//
doms.unshift(h('div', {'class': {'line-top-right': true}}, []))
doms.unshift(h('div', {'class': {'line-bot-right': true}}, []))
}
},
copyBranch(node) {
let parentNode = this.nodeMap.get(node.parentId)
let branchNode = this.$deepCopy(node)
branchNode.name = branchNode.name + '-copy'
this.forEachNode(parentNode, branchNode, (parent, node) => {
let id = this.getRandomId()
console.log(node, '新id =>' + id, '老nodeId:' + node.id)
node.id = id
node.parentId = parent.id
})
parentNode.branchs.splice(parentNode.branchs.indexOf(node), 0, branchNode)
this.$forceUpdate()
},
//
branchMove(node, offset) {
let parentNode = this.nodeMap.get(node.parentId)
let index = parentNode.branchs.indexOf(node)
let branch = parentNode.branchs[index + offset]
parentNode.branchs[index + offset] = parentNode.branchs[index]
parentNode.branchs[index] = branch
this.$forceUpdate()
},
//
isPrimaryNode(node) {
return node &&
(node.type === 'ROOT' || node.type === 'APPROVAL'
|| node.type === 'CC' || node.type === 'DELAY'
|| node.type === 'TRIGGER');
},
//
isBranchNode(node) {
return node && (node.type === 'CONDITIONS' || node.type === 'CONCURRENTS');
},
//
isEmptyNode(node) {
return node && (node.type === 'EMPTY')
},
//
isMergeNode(node) {
return node && (node.type === 'MERGE')
},
//
isConditionNodes(node) {
return node.type === 'CONDITIONS';
},
isConditionNode(node) {
return node.type === 'CONDITION';
},
//
isBranchSubNode(node) {
return node && (node.type === 'CONDITION' || node.type === 'CONCURRENT');
},
//
isConcurrentNodes(node) {
return node.type === 'CONCURRENTS'
},
//
isConcurrentNode(node) {
return node.type === 'CONCURRENT'
},
//id
getRandomId() {
let d = new Date().getTime()
// x 0-9 a-f 32
let uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
let r = (d + Math.random() * 16) % 16 | 0
d = Math.floor(d / 16)
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16)
})
return uuid
// return `node_${new Date().getTime().toString().substring(5)}${Math.round(Math.random() * 9000 + 1000)}`
},
//
selectNode(node) {
this.$store.commit('selectedNode', node)
console.log(node,"node")
if (!this.isConcurrentNode(node)) {
this.$emit('selectedNode', node)
}
},
//
insertNode(type, parentNode) {
console.log("type", type)
this.$refs['_root'].click()
//
let id = this.getRandomId();
this.updateParentId(id, parentNode.id)
let children = {
id: id,
parentId: parentNode.id,
type: type,
}
switch (type) {
case 'APPROVAL':
this.insertApprovalNode(children);
break;
case 'CC':
this.insertCcNode(children);
break;
case 'DELAY':
this.insertDelayNode(children);
break;
case 'TRIGGER':
this.insertTriggerNode(children);
break;
case 'CONDITIONS':
this.insertConditionsNode(children);
break;
case 'CONCURRENTS':
this.insertConcurrentsNode(children);
break;
default:
break;
}
this.$forceUpdate()
},
/**
* 更新父id
* @param newId
* @param oldId
*/
updateParentId(newId, oldId) {
this.dom.map(node => {
if (node.parentId === oldId) {
node.parentId = newId
}
})
},
/**
* 审批人
* @param parentNode
*/
insertApprovalNode(parentNode) {
let node = {
...parentNode,
name: "审批人",
props: this.$deepCopy(DefaultProps.APPROVAL_PROPS)
}
this.dom.push(node)
},
/**
* 抄送人
* @param node
*/
insertCcNode(node) {
let newNode = {
...node,
name: "抄送人",
props: this.$deepCopy(DefaultProps.CC_PROPS)
}
this.dom.push(newNode)
},
/**
* 延时处理
* @param node
*/
insertDelayNode(node) {
let newNode = {
...node,
name: "延时处理",
props: this.$deepCopy(DefaultProps.DELAY_PROPS)
}
this.dom.push(newNode)
},
/**
* 触发器
* @param node
*/
insertTriggerNode(node) {
let newNode = {
...node,
name: "触发器",
props: this.$deepCopy(DefaultProps.TRIGGER_PROPS)
}
this.dom.push(newNode)
},
/**
* 新增条件分支F
* @param node
*/
insertConditionsNode(node) {
let newNode = {
...node,
name: "条件分支",
branchs: [
{
id: this.getRandomId(),
parentId: node.id,
type: "CONDITION",
props: this.$deepCopy(DefaultProps.CONDITION_PROPS),
name: "条件1",
children: {}
}, {
id: this.getRandomId(),
parentId: node.id,
type: "CONDITION",
props: this.$deepCopy(DefaultProps.CONDITION_PROPS),
name: "条件2",
children: {}
}
]
}
this.dom.push(newNode)
let emptyNode = {
id: this.getRandomId(),
parentId: node.id,
type: "EMPTY"
}
this.updateParentId(emptyNode.id, newNode.id)
this.dom.push(emptyNode)
},
/**
* 新增同步运行节点
* @param node
*/
insertConcurrentsNode(node) {
let newNode = {
...node,
name: "并行分支",
branchs: [
{
id: this.getRandomId(),
parentId: node.id,
type: "CONCURRENT",
props: this.$deepCopy(DefaultProps.CONDITION_PROPS),
name: "分支1",
children: {}
}, {
id: this.getRandomId(),
parentId: node.id,
type: "CONCURRENT",
props: this.$deepCopy(DefaultProps.CONDITION_PROPS),
name: "分支2",
children: {}
}
]
}
this.dom.push(newNode)
let emptyNode = {
id: this.getRandomId(),
parentId: node.id,
type: "MERGE"
}
this.updateParentId(emptyNode.id, newNode.id)
this.dom.push(emptyNode)
},
addBranchNode(node) {
if (node.branchs.length < 8) {
node.branchs.push({
id: this.getRandomId(),
parentId: node.id,
name: (this.isConditionNodes(node) ? '条件' : '分支') + (node.branchs.length + 1),
props: this.isConditionNodes(node) ? this.$deepCopy(DefaultProps.CONDITION_PROPS) : {},
type: this.isConditionNodes(node) ? "CONDITION" : "CONCURRENT",
children: {}
})
} else {
this.$message.warning("最多只能添加 8 项😥")
}
},
//
delNode(node) {
//
let parentNode = this.nodeMap.get(node.parentId)
if (parentNode) {
if (this.isBranchNode(parentNode)) {
this.delBranchNode(parentNode, node)
} else {
this.delNodeInDomChange(node.id, parentNode.id)
}
} else {
this.$message.warning("出现错误,找不到上级节点😥")
}
},
//
delBranchNode(parentNode, node) {
let sunNode = this.parentMap.get(node.id)
//,
if (sunNode) {
this.$confirm('当前分支下有子节点,是否继续?', '提示', {
confirmButtonText: '确 定',
cancelButtonText: '取 消',
type: 'warning'
}).then(() => {
//
this.delBranchSunNode(sunNode.id)
this.doDelBranchNode(parentNode, node)
})
return
} else {
//
this.doDelBranchNode(parentNode, node)
}
},
//
delBranchSunNode(id) {
let node = this.parentMap.get(id)
this.delNodeInDomChange(id)
if (node) {
this.delBranchSunNode(node.id)
}
},
//
doDelBranchNode(parentNode, node) {
//2
if (parentNode.branchs.length === 2) {
let nodeList = [...parentNode.branchs]
nodeList.splice(nodeList.indexOf(node), 1)
//
let sunNode = this.parentMap.get(nodeList[0].id)
//
if (sunNode) {
//id
this.updateParentId(parentNode.parentId, sunNode.parentId)
//
let lastNode = this.getLastBranchNode(sunNode.id)
let emptyNode = this.parentMap.get(parentNode.id)
//id
this.updateParentId(lastNode.id, emptyNode.id)
//
this.delNodeInDom(parentNode)
//
this.delNodeInDom(emptyNode)
} else {
//
this.delEntireBranch(parentNode)
}
} else {
parentNode.branchs.splice(parentNode.branchs.indexOf(node), 1)
}
},
//
getLastBranchNode(id) {
let node = this.parentMap.get(id)
if (node) {
return this.getLastBranchNode(node.id)
} else {
return this.nodeMap.get(id)
}
},
delEntireBranch(node) {
//
let emptyNode = this.parentMap.get(node.id)
this.delNodeInDomChange(node.id, node.parentId)
this.delNodeInDomChange(emptyNode.id, emptyNode.parentId)
},
/**
* 从dom中删除
* @param delId
* @param parentId
*/
delNodeInDomChange(delId, parentId) {
this.updateParentId(parentId, delId)
let delNode = this.nodeMap.get(delId)
this.dom.splice(this.dom.indexOf(delNode), 1)
},
delNodeInDom(delNode) {
this.dom.splice(this.dom.indexOf(delNode), 1)
},
validateProcess() {
this.valid = true
let err = []
this.validate(err, this.dom)
return err
},
validateNode(err, node) {
if (this.$refs[node.id].validate) {
this.valid = this.$refs[node.id].validate(err)
}
},
//dom
nodeDomUpdate(node) {
this.$refs[node.id].$forceUpdate()
},
//
forEachNode(parent, node, callback) {
if (this.isBranchNode(node)) {
callback(parent, node)
this.forEachNode(node, node.children, callback)
node.branchs.map(branchNode => {
callback(node, branchNode)
this.forEachNode(branchNode, branchNode.children, callback)
})
} else if (this.isPrimaryNode(node) || this.isEmptyNode(node) || this.isBranchSubNode(node)) {
callback(parent, node)
this.forEachNode(node, node.children, callback)
}
},
//
validate(err, nodeList) {
nodeList.map(node => {
if (this.isPrimaryNode(node)) {
//
this.validateNode(err, node)
} else if (this.isBranchNode(node)) {
node.branchs.map(branchNode => {
//
this.validateNode(err, branchNode)
})
}
})
},
},
watch: {}
}
</script>
<style lang="less" scoped>
._root {
margin: 0 auto;
}
.process-end {
width: 60px;
margin: 0 auto;
margin-bottom: 20px;
border-radius: 15px;
padding: 5px 10px;
font-size: small;
color: #747474;
background-color: #f2f2f2;
box-shadow: 0 0 10px 0 #bcbcbc;
}
.primary-node {
display: flex;
align-items: center;
flex-direction: column;
}
.branch-node {
display: flex;
justify-content: center;
/*border-top: 2px solid #cccccc;
border-bottom: 2px solid #cccccc;*/
}
.branch-node-item {
position: relative;
display: flex;
background: #f5f6f6;
flex-direction: column;
align-items: center;
border-top: 2px solid #cccccc;
border-bottom: 2px solid #cccccc;
&:before {
content: "";
position: absolute;
top: 0;
left: calc(50% - 1px);
margin: auto;
width: 2px;
height: 100%;
background-color: #CACACA;
}
.line-top-left, .line-top-right, .line-bot-left, .line-bot-right {
position: absolute;
width: 50%;
height: 4px;
background-color: #f5f6f6;
}
.line-top-left {
top: -2px;
left: -1px;
}
.line-top-right {
top: -2px;
right: -1px;
}
.line-bot-left {
bottom: -2px;
left: -1px;
}
.line-bot-right {
bottom: -2px;
right: -1px;
}
}
.add-branch-btn {
position: absolute;
width: 80px;
.add-branch-btn-el {
z-index: 999;
position: absolute;
top: -15px;
}
}
.empty-node {
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
}
</style>

View File

@ -7,14 +7,16 @@ import Condition from '@/views/common/process/nodes/ConditionNode.vue'
import Trigger from '@/views/common/process/nodes/TriggerNode.vue'
import Delay from '@/views/common/process/nodes/DelayNode.vue'
import Empty from '@/views/common/process/nodes/EmptyNode.vue'
import Merge from '@/views/common/process/nodes/MergeNode.vue'
import Root from '@/views/common/process/nodes/RootNode.vue'
import End from '@/views/common/process/nodes/ProcessEndNode.vue'
import Node from '@/views/common/process/nodes/Node.vue'
import DefaultProps from "./DefaultNodeProps"
export default {
name: "ProcessTree",
components: {Node, Root, Approval, Cc, Trigger, Concurrent, Condition, Delay, Empty},
components: {Node, Root, Approval, Cc, Trigger, Concurrent, Condition, Delay, Empty,Merge,End},
data() {
return {
valid: true
@ -31,19 +33,25 @@ export default {
return this.$store.state.design.process;
}
},
// eslint-disable-next-line no-unused-vars
render(h, ctx) {
console.log("渲染流程树")
this.nodeMap.clear()
this.parentMap.clear()
this.initMapping(this.dom)
console.log(this.dom)
console.log(this.nodeMap, this.parentMap)
let processTrees = this.getDomTree(h, "admin")
// let endNode = {
// id : this.getRandomId(),
// type: "End"
// }
// this.decodeAppendEndDom(h,endNode,processTrees)
//
processTrees.push(h('div', {style: {'text-align': 'center'}}, [
h('div', {class: {'process-end': true}, domProps: {innerHTML: '流程结束'}})
]))
return h('div', {class: {'_root': true}, ref: '_root'}, processTrees)
// processTrees.push(h('div', {style: {'text-align': 'center'}}, [
// h('div', {class: {'process-end': true}, domProps: {innerHTML: ''}})
// ]))
// return h('div', {class: {'process-end': true}, ref: 'end'}, processTrees)
return h('div', {class:{'_root': true}, ref:'_root'}, processTrees)
// return h('div', {class: {'end-last': true}, ref: 'end'}, processTrees)
},
methods: {
// demo
@ -77,18 +85,27 @@ export default {
'class': {'add-branch-btn-el': true},
props: {size: 'small', round: true},
on: {click: () => this.addBranchNode(node)},
domProps: {innerHTML: `添加${this.isConditionNode(node) ? '条件' : '分支'}`},
domProps: {innerHTML: `添加${this.isConditionNodes(node) ? '条件' : '分支'}`},
}, [])
]));
let bchDom = [h('div', {'class': {'branch-node': true}}, branchItems)]
//
let afterChildDoms = this.getDomTree(h, node.id)
return [h('div', {}, [bchDom, afterChildDoms])]
} else if (this.isMergeNode(node)){
//
let childDoms = this.getDomTree(h, node.id)
this.decodeAppendDom(h, node, childDoms)
return [h('div', {'class': {'empty-node': true}}, childDoms)];
} else if (this.isEmptyNode(node)) {
//
let childDoms = this.getDomTree(h, node.id)
this.decodeAppendDom(h, node, childDoms)
return [h('div', {'class': {'empty-node': true}}, childDoms)];
}else if (this.isEndNode(node)){
let childDoms = this.getDomTree(h, node.id)
this.decodeAppendEndDom(h, node, childDoms)
return [h('div', {'class': {'process-end': true}, ref: 'end'}, childDoms)];
}
return []
},
@ -110,12 +127,44 @@ export default {
}
}, []))
},
decodeAppendEndDom(h, node, dom, props = {}) {
props.config = node
dom.unshift(h(node.type.toLowerCase(), {
props: props,
ref: node.id,
key: node.id,
///
// on: {
// insertNode: type => this.insertNode(type, node),
// delNode: () => this.delNode(node),
// selected: () => this.selectNode(node),
// copy: () => this.copyBranch(node),
// leftMove: () => this.branchMove(node, -1),
// rightMove: () => this.branchMove(node, 1)
// }
}, []))
},
// map,便
initMapping(node) {
node.forEach(node => {
this.nodeMap.set(node.id, node)
this.parentMap.set(node.parentId, node)
})
// if (node typeof list){
//
// }
// if (type == 'object'){
// this.nodeMap.set(node.id, node)
// this.parentMap.set(node.parentId, node)
//
// console.log(node,"'object'")
// }else {
//
// console.log(node,"!object'")
// console.log(node)
node.forEach(nodeItem => {
this.nodeMap.set(nodeItem.id, nodeItem)
this.parentMap.set(nodeItem.parentId, nodeItem)
})
// }
},
//idmap
toMapping(node) {
@ -169,34 +218,64 @@ export default {
|| node.type === 'CC' || node.type === 'DELAY'
|| node.type === 'TRIGGER');
},
//
isBranchNode(node) {
return node && (node.type === 'CONDITIONS' || node.type === 'CONCURRENTS');
},
//
isEmptyNode(node) {
return node && (node.type === 'EMPTY')
},
isEndNode(node) {
return node && (node.type === 'END')
},
//
isMergeNode(node) {
return node && (node.type === 'MERGE')
},
//
isConditionNode(node) {
isConditionNodes(node) {
return node.type === 'CONDITIONS';
},
isConditionNode(node) {
return node.type === 'CONDITION';
},
//
isBranchSubNode(node) {
return node && (node.type === 'CONDITION' || node.type === 'CONCURRENT');
},
isConcurrentNode(node) {
//
isConcurrentNodes(node) {
return node.type === 'CONCURRENTS'
},
//
isConcurrentNode(node) {
return node.type === 'CONCURRENT'
},
//id
getRandomId() {
return `node_${new Date().getTime().toString().substring(5)}${Math.round(Math.random() * 9000 + 1000)}`
let d = new Date().getTime()
// x 0-9 a-f 32
let uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
let r = (d + Math.random() * 16) % 16 | 0
d = Math.floor(d / 16)
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16)
})
return uuid
// return `node_${new Date().getTime().toString().substring(5)}${Math.round(Math.random() * 9000 + 1000)}`
},
//
selectNode(node) {
this.$store.commit('selectedNode', node)
this.$emit('selectedNode', node)
console.log(node,"node")
if (!this.isConcurrentNode(node)) {
this.$emit('selectedNode', node)
}
},
//
insertNode(type, parentNode) {
console.log("type", type)
this.$refs['_root'].click()
//
let id = this.getRandomId();
@ -291,7 +370,7 @@ export default {
this.dom.push(newNode)
},
/**
* 新增条件分支
* 新增条件分支F
* @param node
*/
insertConditionsNode(node) {
@ -337,16 +416,16 @@ export default {
{
id: this.getRandomId(),
parentId: node.id,
type: "CONDITION",
type: "CONCURRENT",
props: this.$deepCopy(DefaultProps.CONDITION_PROPS),
name: "条件1",
name: "分支1",
children: {}
}, {
id: this.getRandomId(),
parentId: node.id,
type: "CONDITION",
type: "CONCURRENT",
props: this.$deepCopy(DefaultProps.CONDITION_PROPS),
name: "条件2",
name: "分支2",
children: {}
}
]
@ -356,7 +435,7 @@ export default {
let emptyNode = {
id: this.getRandomId(),
parentId: node.id,
type: "EMPTY"
type: "MERGE"
}
this.updateParentId(emptyNode.id, newNode.id)
this.dom.push(emptyNode)
@ -367,9 +446,9 @@ export default {
node.branchs.push({
id: this.getRandomId(),
parentId: node.id,
name: (this.isConditionNode(node) ? '条件' : '分支') + (node.branchs.length + 1),
props: this.isConditionNode(node) ? this.$deepCopy(DefaultProps.CONDITION_PROPS) : {},
type: this.isConditionNode(node) ? "CONDITION" : "CONCURRENT",
name: (this.isConditionNodes(node) ? '条件' : '分支') + (node.branchs.length + 1),
props: this.isConditionNodes(node) ? this.$deepCopy(DefaultProps.CONDITION_PROPS) : {},
type: this.isConditionNodes(node) ? "CONDITION" : "CONCURRENT",
children: {}
})
} else {
@ -406,7 +485,7 @@ export default {
this.doDelBranchNode(parentNode, node)
})
return
}else {
} else {
//
this.doDelBranchNode(parentNode, node)
}
@ -420,48 +499,48 @@ export default {
}
},
//
doDelBranchNode(parentNode, node){
doDelBranchNode(parentNode, node) {
//2
if (parentNode.branchs.length === 2){
if (parentNode.branchs.length === 2) {
let nodeList = [...parentNode.branchs]
nodeList.splice(nodeList.indexOf(node), 1)
//
let sunNode = this.parentMap.get(nodeList[0].id)
//
if (sunNode){
if (sunNode) {
//id
this.updateParentId(parentNode.parentId,sunNode.parentId)
this.updateParentId(parentNode.parentId, sunNode.parentId)
//
let lastNode = this.getLastBranchNode(sunNode.id)
let emptyNode = this.parentMap.get(parentNode.id)
//id
this.updateParentId(lastNode.id,emptyNode.id)
this.updateParentId(lastNode.id, emptyNode.id)
//
this.delNodeInDom(parentNode)
//
this.delNodeInDom(emptyNode)
}else {
} else {
//
this.delEntireBranch(parentNode)
}
}else {
} else {
parentNode.branchs.splice(parentNode.branchs.indexOf(node), 1)
}
},
//
getLastBranchNode(id){
getLastBranchNode(id) {
let node = this.parentMap.get(id)
if (node){
if (node) {
return this.getLastBranchNode(node.id)
}else {
} else {
return this.nodeMap.get(id)
}
},
delEntireBranch(node){
delEntireBranch(node) {
//
let emptyNode = this.parentMap.get(node.id)
this.delNodeInDomChange(node.id,node.parentId)
this.delNodeInDomChange(emptyNode.id,emptyNode.parentId)
this.delNodeInDomChange(node.id, node.parentId)
this.delNodeInDomChange(emptyNode.id, emptyNode.parentId)
},
/**
@ -472,10 +551,10 @@ export default {
delNodeInDomChange(delId, parentId) {
this.updateParentId(parentId, delId)
let delNode = this.nodeMap.get(delId)
this.dom.splice(this.dom.indexOf(delNode),1)
this.dom.splice(this.dom.indexOf(delNode), 1)
},
delNodeInDom(delNode){
this.dom.splice(this.dom.indexOf(delNode),1)
delNodeInDom(delNode) {
this.dom.splice(this.dom.indexOf(delNode), 1)
},
validateProcess() {
this.valid = true
@ -508,11 +587,11 @@ export default {
},
//
validate(err, nodeList) {
nodeList.map(node=>{
if (this.isPrimaryNode(node)){
nodeList.map(node => {
if (this.isPrimaryNode(node)) {
//
this.validateNode(err, node)
}else if (this.isBranchNode(node)){
} else if (this.isBranchNode(node)) {
node.branchs.map(branchNode => {
//
this.validateNode(err, branchNode)
@ -535,6 +614,7 @@ export default {
margin: 0 auto;
margin-bottom: 20px;
border-radius: 15px;
text-align: center;
padding: 5px 10px;
font-size: small;
color: #747474;
@ -542,6 +622,7 @@ export default {
box-shadow: 0 0 10px 0 #bcbcbc;
}
.primary-node {
display: flex;
align-items: center;

View File

@ -38,9 +38,10 @@ export default {
return {}
},
computed:{
selectedNode(){
this.$store.state.selectedNode
}
// eslint-disable-next-line vue/return-in-computed-property
// selectedNode(){
// this.$store.state.selectedNode
// }
},
methods: {
addApprovalNode(){

View File

@ -8,7 +8,7 @@
</template>
</el-table-column>
<el-table-column prop="readOnly" label="只读" width="80">
<template slot="header" slot-scope="scope">
<template slot="header">
<el-radio label="R" v-model="permSelect" @change="allSelect('R')">只读</el-radio>
</template>
<template slot-scope="scope">
@ -16,7 +16,7 @@
</template>
</el-table-column>
<el-table-column prop="editable" label="可编辑" width="90" v-if="nowNode.type !== 'CC'">
<template slot="header" slot-scope="scope">
<template slot="header">
<el-radio label="E" v-model="permSelect" @change="allSelect('E')">可编辑</el-radio>
</template>
<template slot-scope="scope">
@ -24,7 +24,7 @@
</template>
</el-table-column>
<el-table-column prop="hide" label="隐藏" width="80">
<template slot="header" slot-scope="scope">
<template slot="header">
<el-radio label="H" v-model="permSelect" @change="allSelect('H')">隐藏</el-radio>
</template>
<template slot-scope="scope">

View File

@ -3,7 +3,7 @@
@selected="$emit('selected')" @delNode="$emit('delNode')" @insertNode="type => $emit('insertNode', type)"
placeholder="请设置审批人" header-bgc="#ff943e" header-icon="el-icon-s-check"/>
</template>
<!--审批人节点-->
<script>
import Node from './Node'

View File

@ -3,7 +3,7 @@
@selected="$emit('selected')" @delNode="$emit('delNode')" @insertNode="type => $emit('insertNode', type)"
placeholder="请设置抄送人" header-bgc="#3296fa" header-icon="el-icon-s-promotion"/>
</template>
<!--抄送节点-->
<script>
import Node from './Node'

View File

@ -1,5 +1,6 @@
<template>
<div class="node">
<!-- 并行分支选择后右侧出现操作面板,占时不需要 <div class="node-body" @click="$emit('selected')">-->
<div class="node-body" @click="$emit('selected')">
<div class="node-body-left" @click.stop="$emit('leftMove')" v-if="level > 1">
<i class="el-icon-arrow-left"></i>
@ -32,7 +33,7 @@
</div>
</div>
</template>
<!--并行节点-->
<script>
import InsertButton from '@/views/common/InsertButton.vue'

View File

@ -37,6 +37,7 @@
</div>
</template>
<script>
import InsertButton from '@/views/common/InsertButton.vue'
import {ValueType} from '@/views/common/form/ComponentsConfigExport'

View File

@ -3,7 +3,7 @@
@selected="$emit('selected')" @delNode="$emit('delNode')" @insertNode="type => $emit('insertNode', type)"
placeholder="请设置延时时间" header-bgc="#f25643" header-icon="el-icon-time"/>
</template>
<!--延时器节点-->
<script>
import Node from './Node'

View File

@ -0,0 +1,20 @@
<template>
<node :show="false" :merge="true" @insertNode="type => $emit('insertNode', type)"/>
</template>
<script>
import Node from './Node'
export default {
name: "MergeNode",
components: {Node},
data() {
return {}
},
methods: {}
}
</script>
<style scoped>
</style>

View File

@ -21,6 +21,7 @@
</div>
</div>
<div class="node-footer">
<div v-if="merge" class="branch-merge"><img data-v-1e7b1da5="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAABXlJREFUeF7tmm2IVGUUx3/nLkQUqxmkpAVhSPUllZX8EEGhvVgZQWCU6wcpsqi2mXtnoaBwoqLCufeO9oJYUJQiFZWlZPQCfYiIXkylstTyS1oWWeYWCe6cuLsz7t3r3Ll3du6907oz35bnPM9z/r895zznmWeECf6RCa6fDoBOBExwAp0UmOAB0CmCnRTopECbCZi2nivK1CMD7FpXlH+ydqctKZBz9QyjwkqFG4HzfKK/0gpvl/ulmBWIzAHkVmlRDFY2EihwwLFkRhYQxgzAtHW2CpcBc4CpOsg26eK7yVPYVFwu/9ZzPufq2VLhQBxhAk85lvSF2Y5l/3prjQlAvqR3IjwJTKqz6DeGssQuyLfBsbyjz6PcFgeAZyOwzLFk/QnrjHH/RACYtj6ncHuUCDWYXs7Lz367XEn3inB+1NzauMLGsiW3+u1b2b9lAH22LuiCD2IJED5yTbmiZpt3dAbKT7Hmjhjtdi25oPZnK/uH7dtUCpi2vqVwQ1wRWuHhWkW3StpTEb6IO3fIThhwTemuzWll/0QA5G39FTgrtghhs2vKELA7inra6d38HXvusOEnriWXHo+iFvZvGUDfap3VdYzdzQgIHmd5W7cBc2Ovoax1C3KXZ5/E/i3VgCQciNMD+J1Ug55yXjxo7QfgOdFKCvjyeL/C9MgoEBa5przrt0ti/+C+mRVB/8amrWsU7m2Ql/c5lqwJjre9CDZ1DMFnriXzw0SatvZW4FqBW6o2vwGvCGxyLPmw3rym9g8cwy0XQV8Ix2qEgH0C1ziWNCyceVu1uvZrriVLGqVGsainHO7mRyDynlCvEWupCI7Kxcat6BFg+OwW9ohyfSMIcQF44v/sZovAlRH1I7QVTwyAt1Cjy8hfh9hYvepGQogDoI74HYbSXzHwusTYl7FEAURVcdPWN+NAiAJQTzzCda4p+6N8iDPe1CkQZ8FAtY+E0AhA2uKHszTlT1QkhAHIQnwmAKr1IjQS6gHISnxmABpBCALIUnymAMIgKHxf6wMmH6E3cNTtSLLgZXoKNOgAR6UDyqyq7esKk3znfOriM48AXzc5AmGE1EFgWvXPTMS3DcAJ6TA6XDIT31YAoRCEc5JqcuKc8Kn3AVFO+E4BryvJVHzbI8BzwAdgi2vJ4ihgSY//nyIg8jqctPi2RYBp61wV5qsyR2BFVdhBhBe0wtdisNU15VAagoNrZh4BOVsfFcVCODVUoLBn6E2hIBvShpApgLyt3nvhRXFFCWxwLOmNaz8Wu8wA5G31ntQWNOukwD2OJc80Oy+ufSYAciVdJsJLcZ0K2nV1MbuUk51jnd9oXuoACmW9eHCQj49/T+j3RtiJslPgFxXmoVxe11nhPdeUq8clANPWPoXVQef9D6e1saEHVINHUBYF7Q1lnl2QL5OGkHoE5G19GRhVyBQ+L1tyST0xoa/Iygq3IOvGI4BdwIWjHBeecE15IExM3tYfgJmBOetcU2o9Q2IcsoiAw8Gf0qhyU7kgb4QCcPRTlNGvSspmtzD81J7kJ30AJX0fYeHo2seLjiXLG0TA78CZ/nGFB8uWPJakeG+t9AE4+jjK/XGLWtgTusBix5It4w5ArqRLRTjhl14IW40KD/kre66ki0R4p57IrgozS/2yb9wByDvqhbKX07Xv/oIavMfOP6pFb0pdgcqrbkFuTlp8JingbRIaBfEUHUOYltbtMPUaUNNo2rpeYWk8zSNWqvSmeSvMDIAnybT1boWnY0I4aigL7YJ4bXRqn0wBeCqG7gYVVqFcFapKWXt0gP5nizKQmvLqwpkDqAkaanmhB4MelOkI27XCDjHY7pqyN23htfXbBiArgVH7dABEETrZxzsRcLL/h6P0/Qc1qphfvB2K3wAAAABJRU5ErkJggg==" alt=""></div>
<div class="btn">
<insert-button @insertNode="type => $emit('insertNode', type)"></insert-button>
</div>
@ -45,6 +46,11 @@ export default {
type: Boolean,
default: true
},
//
merge: {
type: Boolean,
default: false
},
//
content: {
type: String,
@ -175,6 +181,19 @@ export default {
.node-footer{
position: relative;
.branch-merge{
font-size: 12px;
display: flex;
width: 38px;
border-radius: 50%;
left: 0;
right: 0;
margin: -20px auto 0;
background: #fff;
justify-content: center;
flex-direction: column;
box-shadow: 0 0 5px 0 #d8d8d8;
}
.btn{
width: 100%;
display: flex;

View File

@ -0,0 +1,16 @@
<template>
<div>
流程结束
</div>
</template>
<script>
export default {
name: "ProcessEndNode"
}
</script>
<style scoped>
</style>

View File

@ -3,10 +3,9 @@
@selected="$emit('selected')" @insertNode="type => $emit('insertNode', type)"
placeholder="所有人" header-bgc="#576a95" header-icon="el-icon-user-solid"/>
</template>
<!--根节点-->
<script>
import Node from './Node'
export default {
name: "RootNode",
components: {Node},

View File

@ -3,7 +3,7 @@
@selected="$emit('selected')" @delNode="$emit('delNode')" @insertNode="type => $emit('insertNode', type)"
placeholder="请设置触发器" header-bgc="#47bc82" header-icon="el-icon-set-up"/>
</template>
<!--触发器节点-->
<script>
import Node from './Node'