Open ZhaoYu8 opened 1 year ago
<!--
* @Author: 赵宇
* @Description: 流程编辑
* @Date: 2023-02-09 13:40:57
* @LastEditTime: 2023-02-21 14:23:52
* @LastEditors: zhao 13370229059@163.com
* @FilePath: \pcj\src\page\flow\components\flowEdit.vue
-->
<template>
<div class="flow">
<z-button icon="check" @click="onCheck" class="ml-10 mt-10"> 确认 </z-button>
<SuperFlow
ref="superFlow"
:node-list="params.nodeList"
:link-list="params.linkList"
:graph-menu="params.graphMenuList"
:node-menu="params.nodeMenuList"
:link-menu="params.linkMenuList"
:enter-intercept="params.enterIntercept"
:output-intercept="params.outputIntercept"
>
<template v-slot:node="{ meta }">
<div :class="`flow-node flow-node-${meta.prop}`" :ref="'flow_' + meta.id">
<header v-if="['end', 'start'].includes(meta.prop)">{{ meta.taskName }}</header>
<el-input v-model="meta.taskName" v-else :class="`flow-node-input-${meta.prop}`"></el-input>
<section v-if="!['end', 'start'].includes(meta.prop)">
<el-select v-model="meta.taskType">
<el-option v-for="item in taskOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
</section>
</div>
</template>
<template v-slot:menuItem="meta">
<span class="super-flow__menu-item-content" v-if="meta.item.disabled">{{ meta.item.label }}</span>
</template>
</SuperFlow>
<nodeEdit v-model="state.nodeShow" :editData="state.editData" :nodeList="state.nodeList" @onSave="onSave" />
</div>
</template>
<script setup>
import nodeEdit from '@/page/flow/components/nodeEdit.vue';
import { flowNodeDefault } from '@/page/flow/flow.js';
import { SuperFlow } from 'vue3-super-flow';
import { taskOptions } from '@/config/data';
import 'vue3-super-flow/dist/style.css';
let route = useRoute();
let router = useRouter();
let $message = inject('$message');
let nodeId = ref(1000);
let superFlow = ref();
let getOnlyId = () => {
return ++nodeId.value;
};
let urlParams = computed(() => route.query);
// 流程值处理
let params = reactive({
nodeList: [],
linkList: [],
graphMenuList: [
[
{
label: '开始节点',
disable(graph) {
return !!graph.nodeList.find(node => node.meta.prop === 'start');
},
selected: (graph, coordinate) => {
const id = getOnlyId();
let obj = {
id,
width: 70,
height: 40,
coordinate,
meta: flowNodeDefault({
id,
prop: 'start',
taskName: '开始',
taskType: 0
})
};
graph.addNode(obj);
}
},
{
label: '添加节点',
disable: false,
selected: (graph, coordinate) => {
const id = getOnlyId();
let obj = {
id,
width: 200,
height: 100,
coordinate,
meta: flowNodeDefault({
id,
prop: 'approval',
taskName: '节点' + (nodeId.value - 1000),
taskType: 1
})
};
console.log(graph);
graph.addNode(obj);
}
},
{
label: '完成节点',
disable(graph) {
return !!graph.nodeList.find(point => point.meta.prop === 'end');
},
selected: (graph, coordinate) => {
const id = getOnlyId();
let obj = {
id,
width: 70,
height: 40,
coordinate, // 坐标
meta: flowNodeDefault({
id,
prop: 'end',
taskName: '完成',
taskType: 999
})
};
graph.addNode(obj);
}
}
]
],
nodeMenuList: [
[
{
label: '编辑',
disable: graph => {
// 修改的时候
if (['start', 'end'].includes(graph.meta.prop)) {
return true;
}
return false;
},
selected: node => {
let { nodeList } = node.graph;
console.log(nodeList, node);
state.editData = node.meta;
// 这里处理掉 开始 结束节点,省的传递子组件要处理
state.nodeList = nodeList.map(r => r.meta).filter(r => ![0, 999].includes(r.taskType));
state.nodeShow = true;
}
},
{
label: '删除',
disable: graph => {
return ['start', 'end'].includes(graph.meta.prop);
},
selected: (node, coordinate) => {
node.remove();
}
}
]
],
linkMenuList: [
[
{
label: '删除',
disable: false,
selected(link, coordinate) {
link.remove();
}
}
]
],
// 连续结束限制。
enterIntercept: (formNode, toNode, graph) => {
const formType = formNode.meta.prop;
switch (toNode.meta.prop) {
case 'start':
return false;
case 'approval':
return ['start', 'approval'].includes(formType);
case 'end':
return ['approval'].includes(formType);
default:
return true;
}
},
// 连线限制,只要不是结束节点,都可以开始连线
outputIntercept: (node, graph) => {
return !(node.meta.prop === 'end');
}
});
let state = reactive({
nodeShow: false,
editData: {},
nodeList: []
});
// 点击保存
const onCheck = () => {
let type = false;
if (!superFlow.value) return;
let graph = superFlow.value.graph.toJSON();
let { nodeList, linkList } = graph;
// 筛出 开始、结束节点 筛出 非开始、结束节点
let nodeResult = [nodeList.filter(r => [0, 999].includes(r.meta.taskType)), nodeList.filter(r => ![0, 999].includes(r.meta.taskType))];
// 必须具备开始 和 结束 节点 。 并且起码要有一个 任务节点
type = nodeResult[0].length === 2 && nodeResult[1].length;
// type 为真,才有必要判断线对不对
if (type) {
// 开始和结束 必须都要有连线
let likeResult = [
linkList.filter(r => r.startId === nodeResult[0].filter(n => n.meta.taskType === 0)[0].id),
linkList.filter(r => r.endId === nodeResult[0].filter(n => n.meta.taskType === 999)[0].id)
];
type = likeResult[0].length && likeResult[1].length; // 都可以存在多条分支分出去 ,也可以存在多条链接结束
}
if (type) {
let arr = nodeList.filter(r => ![0, 999].includes(r.meta.taskType));
// 判断除了开始 和 结束 ,其他节点 都必须要有开始 和结束 二种连线
arr.map(r => {
// 如果为 false 的就不要往下执行了!
if (!type) return;
let obtain = [linkList.filter(n => n.startId === r.id), linkList.filter(n => n.endId === r.id)];
type = obtain[0].length && obtain[1].length;
});
}
if (!type) {
$message.warning('流程错误,请检查流程图配置!');
return;
}
// 如果是业务单 必须要有一个发货节点。还只能有一个
if (Number(urlParams.value.type) === 1) {
if (nodeList.filter(r => r.meta.taskType === 5).length !== 1) {
$message.warning('业务单必须要有发货节点,有且只能有一个!');
return;
}
}
// 如果是采购单 必须要有一个采购入库节点。还只能有一个
if (Number(urlParams.value.type) === 2) {
if (nodeList.filter(r => r.meta.taskType === 3).length !== 1) {
$message.warning('采购单必须要有采购入库节点,有且只能有一个!');
return;
}
}
templateSave(nodeList, linkList);
};
const templateSave = async (nodeList, linkList) => {
http.post('TemplateProgress/CreateOrUpdate', {
id: 0,
formSourceType: urlParams.value.type,
processJson: JSON.stringify({ nodeList, linkList })
});
$message.success('创建成功!');
router.push({
path: 'flow',
query: { type: urlParams.value.type }
});
};
// 处理节点编辑
const onSave = val => {
let nodeList = superFlow.value.graph.nodeList;
const index = nodeList.findIndex(r => r.meta.id === val.id);
console.log(nodeList, index);
nodeList[index].meta = { ...val };
state.nodeShow = false;
};
</script>
<style lang="scss" scoped>
.flow {
height: 100%;
width: 100%;
background-color: #fff;
position: relative;
}
</style>
<style lang="scss">
.super-flow__node {
color: #fff;
border: 0 !important;
border-radius: 4px;
overflow: hidden;
.flow-node {
height: 100%;
display: flex;
flex-direction: column;
section {
padding: 10px;
}
header {
border-radius: 5px;
font-size: 17px;
height: 40px;
line-height: 40px;
padding: 0 12px;
background-color: var(--el-color-warning);
text-align: center;
}
&-start {
header {
background-color: var(--el-color-primary);
}
}
&-end {
header {
background-color: var(--el-color-danger);
}
}
}
.flow-node-input-approval {
.el-input__wrapper {
background-color: var(--el-color-warning);
box-shadow: none;
border-radius: 0;
input {
color: #fff;
}
}
}
}
.super-flow__menu-container {
.super-flow__menu {
padding: 0;
border: 0;
&-line {
margin: 0 auto;
width: 96%;
display: none;
}
&-item {
padding: 10px;
width: 100%;
&:nth-child(even) {
background-color: #f2f6fc;
}
&:hover {
background-color: #55abfc;
color: #fff;
}
&-icon {
display: none;
}
&-content {
width: inherit;
color: inherit;
}
}
}
.is-disabled {
display: none;
background-color: #efefef;
&:hover {
background-color: #efefef;
color: #000;
}
}
}
</style>
会在周末进行修复,如果你已经完成可以提交fork...
会在周末进行修复,如果你已经完成可以提交fork...
顺便修复下,无法的滚动的问题。 看代码是监听了onwheel事件。然后preventDefault 我现在是去编译后js里面删了 preventDefault() 事件。
请补充完整信息, 或示例代码...