Toggle navigation
Toggle navigation
This project
Loading...
Sign in
Hooke
/
vue-flow-editor
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Snippets
Network
Create a new issue
Builds
Commits
Issue Boards
Authored by
hookehuyr
2023-11-15 16:00:57 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
93881aa18205b92506589443f0c9dd2789146c68
93881aa1
1 parent
0aa8a6e5
调整单击节点操作逻辑
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
131 additions
and
216 deletions
doc/App.vue
doc/data.js
src/editor/vue-flow-editor.tsx
doc/App.vue
View file @
93881aa
...
...
@@ -14,14 +14,16 @@
:beforeAdd="handleBeforeAdd"
:afterAdd="handleAfterAdd"
@dragend-node="onDragEndNode"
@dblclick-node="onDbl
c
lickNode"
@dblclick-node="onDbl
C
lickNode"
@dblclick-edge="onDblClickEdge"
:activityConfig="state.activityConfig"
:controlConfig="state.controlConfig"
:toolbarButtonHandler="toolbarButtonHandler"
>
<!-- :activityConfig="state.activityConfig" -->
<!-- @click-node="onClickNode" -->
<!-- 左侧菜单 -->
<template v-slot:menu>
<vue-flow-edit-menu-group label="活动节点" value>
<
!-- <
vue-flow-edit-menu-group label="活动节点" value>
<vue-flow-edit-menu
v-for="(value, key) in state.activityConfig"
:key="key"
...
...
@@ -34,8 +36,8 @@
</div>
</template>
</vue-flow-edit-menu>
</vue-flow-edit-menu-group>
<vue-flow-edit-menu-group label="
控制
节点" value>
</vue-flow-edit-menu-group>
-->
<vue-flow-edit-menu-group label="
操作
节点" value>
<!-- 注意 key 值的绑定 -->
<vue-flow-edit-menu
v-for="(value, key) in state.controlConfig"
...
...
@@ -50,18 +52,18 @@
</template>
</vue-flow-edit-menu>
</vue-flow-edit-menu-group>
<vue-flow-edit-menu-group
<
!-- <
vue-flow-edit-menu-group
v-for="(group, groupIndex) in state.menuData"
:label="group.label"
:key="groupIndex"
value
:value="true"
>
<vue-flow-edit-menu
v-for="(menu, menuIndex) in group.menus"
:key="menuIndex"
:model="menu"
/>
</vue-flow-edit-menu-group>
</vue-flow-edit-menu-group>
-->
</template>
<!-- 右侧表单 -->
<template v-slot:model>
...
...
@@ -182,7 +184,7 @@
<el-form-item label="活动副标题">
<el-input v-model="state.detailModel.desc" />
</el-form-item>
<el-form-item label="活动类型">
<
!-- <
el-form-item label="活动类型">
<el-select v-model="state.detailModel.activity">
<el-option
v-for="(value, key) in state.activityConfig"
...
...
@@ -191,7 +193,7 @@
:value="key"
/>
</el-select>
</el-form-item>
</el-form-item>
-->
</template>
</el-form>
</template>
...
...
@@ -241,6 +243,7 @@ interface myObj {
source: string;
id: string;
label: string;
control: string;
}
interface myEvent {
...
...
@@ -294,42 +297,44 @@ export default {
]
}
],
activityConfig: {
advertisement: {
text: "广告宣传1",
desc: "通过广告宣传新品",
color: "#9283ed",
img: "https://cdn.ipadbiz.cn/oa/advertisement-node.svg"
},
coupon: {
text: "优惠券",
desc: "发放奖励优惠券",
color: "#ed8383",
img: "https://cdn.ipadbiz.cn/oa/coupon-node.svg"
},
crowd: {
text: "用户反馈",
desc: "收集用户反馈信息",
color: "#92dba8",
img: "https://cdn.ipadbiz.cn/oa/crowd-node.svg"
}
},
//
activityConfig: {
//
advertisement: {
//
text: "广告宣传1",
//
desc: "通过广告宣传新品",
//
color: "#9283ed",
//
img: "https://cdn.ipadbiz.cn/oa/advertisement-node.svg"
//
},
//
coupon: {
//
text: "优惠券",
//
desc: "发放奖励优惠券",
//
color: "#ed8383",
//
img: "https://cdn.ipadbiz.cn/oa/coupon-node.svg"
//
},
//
crowd: {
//
text: "用户反馈",
//
desc: "收集用户反馈信息",
//
color: "#92dba8",
//
img: "https://cdn.ipadbiz.cn/oa/crowd-node.svg"
//
}
//
},
controlConfig: {
start: {
id: "start-node",
text: "开始",
desc: "
描述文字
",
desc: "
开始
",
color: "#9283ed",
img: "https://cdn.ipadbiz.cn/oa/advertisement-node.svg"
},
stop
: {
text: "
中止
",
desc: "
描述文字
",
flow
: {
text: "
流程节点
",
desc: "
流程节点
",
color: "#ed8383",
img: "https://cdn.ipadbiz.cn/oa/coupon-node.svg"
},
end: {
id: "end-node",
text: "结束",
desc: "
描述文字
",
desc: "
结束
",
color: "#92dba8",
img: "https://cdn.ipadbiz.cn/oa/crowd-node.svg"
}
...
...
@@ -444,7 +449,17 @@ export default {
*
* @param {Object} e - The event object
*/
function onDblclickNode(e: myEvent) {
function onDblClickNode(e: myEvent) {
const model = G6.Util.clone(e.item.get("model"));
model.style = model.style || {};
model.labelCfg = model.labelCfg || { style: {} };
model.data = model.data ? model.data : {};
state.detailModel = model;
editor.openModel();
}
function onClickNode(e: myEvent) {
const model = G6.Util.clone(e.item.get("model"));
model.style = model.style || {};
model.labelCfg = model.labelCfg || { style: {} };
...
...
@@ -542,13 +557,13 @@ export default {
}
}
if (type === "node") {
if (model.
id === "start-node" || model.id === "end-node
") {
if (model.
control === "start" || model.control === "end
") {
const data = editor.editorState.graph.save();
for (let i = 0; i < data.nodes.length; i++) {
const node = data.nodes[i];
if (node.
id === model.id
) {
if (node.
control === model.control
) {
ElNotification.error(
`只能有一个${model.
id === "start-node
" ? "开始" : "结束"}节点`
`只能有一个${model.
control === "start
" ? "开始" : "结束"}节点`
);
return Promise.reject("reject");
}
...
...
@@ -564,6 +579,8 @@ export default {
* @param {type} type - The type of the event.
*/
function handleAfterAdd(model: myObj, type: string) {
console.log('handleAfterAdd', model);
// TODO: 因为resize会重新绘制,所以可能需要保存操作
if (type === 'node') {
console.log(`新增节点`);
...
...
@@ -591,6 +608,18 @@ export default {
*/
function logData(): void {
let { nodes, edges } = editor.editorState.graph.save();
// console.log("nodes", nodes);
// console.log("edges", edges);
// 使用时需要把自定义节点的类型带过去 activity/control
nodes.forEach((node: { [x: string]: string; shape: string; }) => {
if (node.shape === "activity") {
node['shape'] = 'activity_' + node['activity'];
}
if (node.shape === "control") {
node['shape'] = 'control_' + node['control'];
}
});
nodes = nodes.map(
({ data, id, label, shape, x, y, text, desc, img }) => ({
data,
...
...
@@ -610,17 +639,32 @@ export default {
target,
targetAnchor
}));
console.log(JSON.stringify({ nodes, edges }, null, 2));
// console.log(JSON.stringify({ nodes, edges }, null, 2));
console.log(nodes);
console.log(edges);
}
/**
* 格式化工具栏按钮
*
* @param {Array} buttons - The array of buttons to be filtered
* @return {Array} - The filtered array of buttons
*/
function toolbarButtonHandler(buttons: any[]): Array<any> {
// TAG:测试隐藏缩略图
let map = buttons.filter(item => item.key !== "miniMapSwitcher");
return map;
}
return {
state,
showGrid: true, // 是否开启网格
showMiniMap:
tru
e, // 是否开启缩略图
showMiniMap:
fals
e, // 是否开启缩略图
showMultipleSelect: true, // 编辑器是否可以多选
onDblclickNode,
onClickNode,
onDblClickNode,
onDragEndNode,
onDblClickEdge,
cancel,
...
...
@@ -639,6 +683,7 @@ export default {
onConfirmUserView,
logData,
toolbarButtonHandler,
onRef: (e: any) => (editor = e),
staticPath
...
...
doc/data.js
View file @
93881aa
/*
* @Date: 2023-10-27 09:29:48
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2023-11-15 15:56:03
* @FilePath: /vue-flow-editor/doc/data.js
* @Description: 初始化结构,数据都是固定的
*/
export
const
AppData
=
{
"nodes"
:
[
nodes
:
[
{
"id"
:
"123456"
,
"x"
:
590
,
"y"
:
100
,
"text"
:
"广告宣传"
,
"desc"
:
"通过广告短频宣传"
,
"activity"
:
"advertisement"
,
// 自定义节点的类型
id
:
'start-node'
,
x
:
225
,
y
:
100
,
text
:
'开始'
,
desc
:
''
,
control
:
'start'
,
},
{
"id"
:
"2323456789"
,
"x"
:
1020
,
"y"
:
10
0
,
"text"
:
"优惠券"
,
"desc"
:
"发送奖励优惠券"
,
"activity"
:
"coupon"
,
id
:
'5353453523'
,
x
:
225
,
y
:
21
0
,
text
:
'流程节点'
,
desc
:
''
,
control
:
'flow'
,
},
{
"id"
:
"23234567891"
,
"x"
:
130
,
"y"
:
130
,
"text"
:
"开始"
,
"desc"
:
"发布"
,
"control"
:
"start"
,
id
:
'end-node'
,
x
:
225
,
y
:
335
,
text
:
'结束'
,
desc
:
''
,
control
:
'end'
,
},
{
"data"
:
{},
"id"
:
"start-node"
,
"label"
:
"开始"
,
"shape"
:
"ellipse"
,
"x"
:
380
,
"y"
:
100
},
{
"data"
:
{},
"id"
:
"1588848310120"
,
"label"
:
"主管审批"
,
"shape"
:
"rect"
,
"x"
:
380
,
"y"
:
180
},
{
"data"
:
{},
"id"
:
"1588848322179"
,
"label"
:
"经理审批"
,
"shape"
:
"rect"
,
"x"
:
380
,
"y"
:
260
},
{
"data"
:
{},
"id"
:
"1588848338211"
,
"label"
:
"金额>2万"
,
"shape"
:
"diamond"
,
"x"
:
380
,
"y"
:
340
},
{
"data"
:
{},
"id"
:
"1588848351476"
,
"label"
:
"财务打款"
,
"shape"
:
"rect"
,
"x"
:
380
,
"y"
:
460
},
{
"data"
:
{},
"id"
:
"end-node"
,
"label"
:
"结束"
,
"shape"
:
"ellipse"
,
"x"
:
380
,
"y"
:
540
},
{
"data"
:
{},
"id"
:
"1588848397511"
,
"label"
:
"VIP审批"
,
"shape"
:
"rect"
,
"x"
:
590
,
"y"
:
340
},
{
"data"
:
{
test
:
100
},
"id"
:
"1588848436694"
,
"label"
:
"金额>10万1"
,
"shape"
:
"diamond"
,
"x"
:
780
,
"y"
:
340
},
{
"data"
:
{},
"id"
:
"1588848449431"
,
"label"
:
"CEO审批"
,
"shape"
:
"rect"
,
"x"
:
960
,
"y"
:
460
}
],
"edges"
:
[
edges
:
[
{
"source"
:
"start-node"
,
"sourceAnchor"
:
2
,
"target"
:
"1588848310120"
,
"targetAnchor"
:
0
source
:
'start-node'
,
sourceAnchor
:
2
,
target
:
'5353453523'
,
targetAnchor
:
0
,
},
{
"source"
:
"1588848310120"
,
"sourceAnchor"
:
2
,
"target"
:
"1588848322179"
,
"targetAnchor"
:
0
source
:
'5353453523'
,
sourceAnchor
:
2
,
target
:
'end-node'
,
targetAnchor
:
0
,
},
{
"source"
:
"1588848322179"
,
"sourceAnchor"
:
2
,
"target"
:
"1588848338211"
,
"targetAnchor"
:
0
},
{
"source"
:
"1588848338211"
,
"sourceAnchor"
:
2
,
"target"
:
"1588848351476"
,
"targetAnchor"
:
0
},
{
"source"
:
"1588848351476"
,
"sourceAnchor"
:
2
,
"target"
:
"end-node"
,
"targetAnchor"
:
0
},
{
"source"
:
"1588848338211"
,
"sourceAnchor"
:
3
,
"target"
:
"1588848397511"
,
"targetAnchor"
:
1
},
{
"source"
:
"1588848436694"
,
"sourceAnchor"
:
3
,
"target"
:
"1588848449431"
,
"targetAnchor"
:
0
},
{
"source"
:
"1588848449431"
,
"sourceAnchor"
:
1
,
"target"
:
"1588848351476"
,
"targetAnchor"
:
3
},
{
"source"
:
"1588848436694"
,
"sourceAnchor"
:
2
,
"target"
:
"1588848351476"
,
"targetAnchor"
:
3
},
{
"source"
:
"1588848397511"
,
"sourceAnchor"
:
3
,
"target"
:
"1588848436694"
,
"targetAnchor"
:
1
},
{
"source"
:
"start-node"
,
"sourceAnchor"
:
3
,
"target"
:
"123456"
,
"targetAnchor"
:
1
},
{
"source"
:
"123456"
,
"sourceAnchor"
:
3
,
"target"
:
"2323456789"
,
"targetAnchor"
:
1
},
{
"source"
:
"2323456789"
,
"sourceAnchor"
:
3
,
"target"
:
"end-node"
,
"targetAnchor"
:
3
}
]
],
}
...
...
src/editor/vue-flow-editor.tsx
View file @
93881aa
...
...
@@ -7,9 +7,9 @@ export default {
name: 'vue-flow-editor',
props: {
data: {type: Object}, // 渲染的数据
grid: {type: Boolean, default: true}, // 是否需要网格
miniMap: {type: Boolean, default: false}, // 是否需要缩略图
disabledDragEdge:{type: Boolean}, // 禁用拖拽连线功能
grid: {type: Boolean, default: true},
// 是否需要网格
miniMap: {type: Boolean, default: false},
// 是否需要缩略图
disabledDragEdge:{type: Boolean},
// 禁用拖拽连线功能
disabledUndo: {type: Boolean}, // 禁用撤销以及重做功能
editorTitle: {type: String}, // 编辑器标题
...
...
@@ -29,8 +29,8 @@ export default {
beforeAdd: {type: Function}, // 添加前校验
afterAdd: {type: Function}, // 添加后动作
// TAG: 自定义节点 - 前端注入类型
activityConfig: {type: Object}, // 注册活动节点
controlConfig: {type: Object}, // 注册活动节点
activityConfig: {type: Object},
// 注册活动节点
controlConfig: {type: Object},
// 注册活动节点
},
setup(props, context) {
...
...
@@ -56,6 +56,9 @@ export default {
editorState.graph = graph
commander.init(graph)
graph.on('node:click', (e) => {
context.emit('click-node', e)
})
graph.on('node:dblclick', (e) => {
context.emit('dblclick-node', e)
})
...
...
Please
register
or
login
to post a comment