Compare commits
2 Commits
e798332828
...
21f02660e9
| Author | SHA1 | Date | |
|---|---|---|---|
| 21f02660e9 | |||
| f6e9c9bc70 |
@@ -1,5 +1,5 @@
|
||||
import {PlusCircleFilled, RollbackOutlined, SaveFilled} from '@ant-design/icons'
|
||||
import {Background, BackgroundVariant, Controls, MiniMap, ReactFlow} from '@xyflow/react'
|
||||
import {Background, BackgroundVariant, Controls, MiniMap, Panel, ReactFlow} from '@xyflow/react'
|
||||
import {Button, Dropdown, message, Popconfirm, Space} from 'antd'
|
||||
import {arrToMap, isEqual, randomId, unique} from 'licia'
|
||||
import {useEffect} from 'react'
|
||||
@@ -34,13 +34,6 @@ const FlowableDiv = styled.div`
|
||||
}
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
top: 20px;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.node-card {
|
||||
cursor: default;
|
||||
|
||||
@@ -85,80 +78,6 @@ function FlowEditor(props: FlowEditorProps) {
|
||||
return (
|
||||
<FlowableDiv className="h-full w-full">
|
||||
{contextHolder}
|
||||
<Space className="toolbar">
|
||||
<Dropdown
|
||||
menu={{
|
||||
items: unique(NodeRegistry.map(i => i.group))
|
||||
.map(group => ({
|
||||
type: 'group',
|
||||
label: group,
|
||||
children: NodeRegistry.filter(i => isEqual(group, i.group))
|
||||
.map(i => ({key: i.key, label: i.name, icon: i.icon})),
|
||||
})),
|
||||
onClick: ({key}) => {
|
||||
try {
|
||||
if (commonInfo.debug) {
|
||||
console.info('Add', key, JSON.stringify({nodes, edges, data}))
|
||||
}
|
||||
checkAddNode(key, nodes, edges)
|
||||
|
||||
let nodeId = randomId(10, 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM')
|
||||
let define = NodeRegistryMap[key]
|
||||
|
||||
setDataById(
|
||||
nodeId,
|
||||
{
|
||||
node: {
|
||||
name: define.name,
|
||||
description: define.description,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
addNode({
|
||||
id: nodeId,
|
||||
type: key,
|
||||
position: {x: 100, y: 100},
|
||||
data: {},
|
||||
})
|
||||
} catch (e) {
|
||||
// @ts-ignore
|
||||
messageApi.error(e.toString())
|
||||
}
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Button type="default">
|
||||
<PlusCircleFilled/>
|
||||
新增节点
|
||||
</Button>
|
||||
</Dropdown>
|
||||
<Popconfirm
|
||||
title="返回上一页"
|
||||
description="未保存的流程图将会被丢弃,确认是否返回"
|
||||
onConfirm={() => navigate(-1)}
|
||||
>
|
||||
<Button type="default">
|
||||
<RollbackOutlined/>
|
||||
返回
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
<Button type="primary" onClick={() => {
|
||||
try {
|
||||
if (commonInfo.debug) {
|
||||
console.info('Save', JSON.stringify({nodes, edges, data}))
|
||||
}
|
||||
checkSave(inputSchema, nodes, edges, data)
|
||||
props.onGraphDataChange({nodes, edges, data})
|
||||
} catch (e) {
|
||||
// @ts-ignore
|
||||
messageApi.error(e.toString())
|
||||
}
|
||||
}}>
|
||||
<SaveFilled/>
|
||||
保存
|
||||
</Button>
|
||||
</Space>
|
||||
<ReactFlow
|
||||
nodes={nodes}
|
||||
edges={edges}
|
||||
@@ -179,6 +98,82 @@ function FlowEditor(props: FlowEditorProps) {
|
||||
// @ts-ignore
|
||||
nodeTypes={arrToMap(Object.keys(NodeRegistryMap), key => NodeRegistryMap[key]!.component)}
|
||||
>
|
||||
<Panel position="top-right">
|
||||
<Space className="toolbar">
|
||||
<Dropdown
|
||||
menu={{
|
||||
items: unique(NodeRegistry.map(i => i.group))
|
||||
.map(group => ({
|
||||
type: 'group',
|
||||
label: group,
|
||||
children: NodeRegistry.filter(i => isEqual(group, i.group))
|
||||
.map(i => ({key: i.key, label: i.name, icon: i.icon})),
|
||||
})),
|
||||
onClick: ({key}) => {
|
||||
try {
|
||||
if (commonInfo.debug) {
|
||||
console.info('Add', key, JSON.stringify({nodes, edges, data}))
|
||||
}
|
||||
checkAddNode(key, nodes, edges)
|
||||
|
||||
let nodeId = randomId(10, 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM')
|
||||
let define = NodeRegistryMap[key]
|
||||
|
||||
setDataById(
|
||||
nodeId,
|
||||
{
|
||||
node: {
|
||||
name: define.name,
|
||||
description: define.description,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
addNode({
|
||||
id: nodeId,
|
||||
type: key,
|
||||
position: {x: 100, y: 100},
|
||||
data: {},
|
||||
})
|
||||
} catch (e) {
|
||||
// @ts-ignore
|
||||
messageApi.error(e.toString())
|
||||
}
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Button type="default">
|
||||
<PlusCircleFilled/>
|
||||
新增节点
|
||||
</Button>
|
||||
</Dropdown>
|
||||
<Popconfirm
|
||||
title="返回上一页"
|
||||
description="未保存的流程图将会被丢弃,确认是否返回"
|
||||
onConfirm={() => navigate(-1)}
|
||||
>
|
||||
<Button type="default">
|
||||
<RollbackOutlined/>
|
||||
返回
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
<Button type="primary" onClick={() => {
|
||||
try {
|
||||
if (commonInfo.debug) {
|
||||
console.info('Save', JSON.stringify({nodes, edges, data}))
|
||||
}
|
||||
checkSave(inputSchema, nodes, edges, data)
|
||||
props.onGraphDataChange({nodes, edges, data})
|
||||
} catch (e) {
|
||||
// @ts-ignore
|
||||
messageApi.error(e.toString())
|
||||
}
|
||||
}}>
|
||||
<SaveFilled/>
|
||||
保存
|
||||
</Button>
|
||||
</Space>
|
||||
</Panel>
|
||||
<Controls/>
|
||||
<MiniMap/>
|
||||
<Background variant={BackgroundVariant.Cross} gap={20} size={3}/>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {CopyFilled, DeleteFilled, EditFilled} from '@ant-design/icons'
|
||||
import {type Edge, Handle, type Node, type NodeProps, Position} from '@xyflow/react'
|
||||
import {type Edge, Handle, type Node, type NodeProps, NodeToolbar, Position} from '@xyflow/react'
|
||||
import type {Schema} from 'amis'
|
||||
import {Button, Card, Drawer} from 'antd'
|
||||
import {Button, Card, Drawer, Space, Tooltip} from 'antd'
|
||||
import {type JSX, useCallback, useState} from 'react'
|
||||
import styled from 'styled-components'
|
||||
import {amisRender, commonInfo, horizontalFormOptions} from '../../../util/amis.tsx'
|
||||
@@ -247,37 +247,42 @@ const AmisNode: (props: AmisNodeProps) => JSX.Element = ({
|
||||
>
|
||||
{editDrawerForm}
|
||||
</Drawer>
|
||||
<NodeToolbar>
|
||||
<Space>
|
||||
<Tooltip title="复制节点">
|
||||
<Button
|
||||
className="text-secondary"
|
||||
disabled
|
||||
type="text"
|
||||
size="small"
|
||||
icon={<CopyFilled/>}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip title="编辑节点">
|
||||
<Button
|
||||
className="text-secondary"
|
||||
type="text"
|
||||
size="small"
|
||||
icon={<EditFilled/>}
|
||||
onClick={() => onOpenEditDrawerClick()}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip title="删除节点">
|
||||
<Button
|
||||
className="text-secondary"
|
||||
type="text"
|
||||
size="small"
|
||||
icon={<DeleteFilled/>}
|
||||
onClick={() => onRemoveClick()}
|
||||
/>
|
||||
</Tooltip>
|
||||
</Space>
|
||||
</NodeToolbar>
|
||||
<Card
|
||||
className="node-card"
|
||||
title={nodeName}
|
||||
extra={<span className="text-gray-300 text-xs">{id}</span>}
|
||||
size="small"
|
||||
actions={[
|
||||
<Button
|
||||
className="text-secondary"
|
||||
disabled
|
||||
type="text"
|
||||
size="small"
|
||||
icon={<CopyFilled/>}
|
||||
block
|
||||
/>,
|
||||
<Button
|
||||
className="text-secondary"
|
||||
type="text"
|
||||
size="small"
|
||||
icon={<EditFilled/>}
|
||||
block
|
||||
onClick={() => onOpenEditDrawerClick()}
|
||||
/>,
|
||||
<Button
|
||||
className="text-secondary"
|
||||
type="text"
|
||||
size="small"
|
||||
icon={<DeleteFilled/>}
|
||||
block
|
||||
onClick={() => onRemoveClick()}
|
||||
/>,
|
||||
]}
|
||||
>
|
||||
<div className="card-description p-2 text-secondary text-sm">
|
||||
{nodeDescription}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import type {NodeProps} from '@xyflow/react'
|
||||
import {Tag} from 'antd'
|
||||
import React, {useCallback} from 'react'
|
||||
import React, {useCallback, useEffect} from 'react'
|
||||
import {useContextStore} from '../store/ContextStore.ts'
|
||||
import {useDataStore} from '../store/DataStore.ts'
|
||||
import {useFlowStore} from '../store/FlowStore.ts'
|
||||
import AmisNode, {EndNodeHandler, inputsFormColumns} from './AmisNode.tsx'
|
||||
import AmisNode, {inputsFormColumns, NormalNodeHandler, outputsFormColumns} from './AmisNode.tsx'
|
||||
|
||||
const typeMap: Record<string, string> = {
|
||||
default: '默认',
|
||||
@@ -15,11 +15,24 @@ const typeMap: Record<string, string> = {
|
||||
|
||||
const TemplateNode = (props: NodeProps) => {
|
||||
const {getNodes, getEdges} = useFlowStore()
|
||||
const {getData, getDataById} = useDataStore()
|
||||
const {getData, getDataById, mergeDataById} = useDataStore()
|
||||
const {getInputSchema} = useContextStore()
|
||||
|
||||
const nodeData = getDataById(props.id)
|
||||
|
||||
useEffect(() => {
|
||||
mergeDataById(
|
||||
props.id,
|
||||
{
|
||||
outputs: {
|
||||
text: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
}, [props.id])
|
||||
|
||||
const columnsSchema = useCallback(
|
||||
() => [
|
||||
...inputsFormColumns(props.id, getInputSchema(), getNodes(), getEdges(), getData()),
|
||||
@@ -55,6 +68,7 @@ const TemplateNode = (props: NodeProps) => {
|
||||
min_height: 500,
|
||||
},
|
||||
},
|
||||
...outputsFormColumns(false, true),
|
||||
],
|
||||
[props.id],
|
||||
)
|
||||
@@ -71,7 +85,7 @@ const TemplateNode = (props: NodeProps) => {
|
||||
: <></>
|
||||
}
|
||||
columnSchema={columnsSchema}
|
||||
handler={<EndNodeHandler/>}
|
||||
handler={<NormalNodeHandler/>}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user