Compare commits
4 Commits
53638a8a6d
...
566dfef208
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
566dfef208 | ||
| 1cba0f4422 | |||
| ab56385c8a | |||
| b58c34443f |
@@ -1,8 +1,17 @@
|
|||||||
import {ProLayout} from '@ant-design/pro-components'
|
import {ProLayout} from '@ant-design/pro-components'
|
||||||
|
import {ConfigProvider} from 'antd'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {Outlet, useLocation, useNavigate} from 'react-router'
|
import {Outlet, useLocation, useNavigate} from 'react-router'
|
||||||
import {menus} from '../route.tsx'
|
import {menus} from '../route.tsx'
|
||||||
import {ConfigProvider} from 'antd'
|
|
||||||
|
const apps: { title: string, desc: string, url: string, icon?: string }[] = [
|
||||||
|
{
|
||||||
|
icon: 'http://132.126.207.124:8686/udal-manager/static/favicon.ico',
|
||||||
|
title: 'CSV-HUDI处理平台',
|
||||||
|
desc: 'Hudi 批量割接、稽核任务管理平台',
|
||||||
|
url: 'http://132.126.207.124:8686/udal-manager/',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
const App: React.FC = () => {
|
const App: React.FC = () => {
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
@@ -10,6 +19,8 @@ const App: React.FC = () => {
|
|||||||
return (
|
return (
|
||||||
<ProLayout
|
<ProLayout
|
||||||
token={{
|
token={{
|
||||||
|
colorTextAppListIcon: '#dfdfdf',
|
||||||
|
colorTextAppListIconHover: '#ffffff',
|
||||||
header: {
|
header: {
|
||||||
colorBgHeader: '#292f33',
|
colorBgHeader: '#292f33',
|
||||||
colorHeaderTitle: '#ffffff',
|
colorHeaderTitle: '#ffffff',
|
||||||
@@ -21,6 +32,8 @@ const App: React.FC = () => {
|
|||||||
colorTextRightActionsItem: '#dfdfdf',
|
colorTextRightActionsItem: '#dfdfdf',
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
|
appList={apps}
|
||||||
|
disableMobile={true}
|
||||||
logo={<img src="icon.png" alt="logo"/>}
|
logo={<img src="icon.png" alt="logo"/>}
|
||||||
title="Hudi 服务总台"
|
title="Hudi 服务总台"
|
||||||
route={menus}
|
route={menus}
|
||||||
@@ -36,14 +49,14 @@ const App: React.FC = () => {
|
|||||||
contentStyle={{backgroundColor: 'white', padding: '10px 10px 10px 20px'}}
|
contentStyle={{backgroundColor: 'white', padding: '10px 10px 10px 20px'}}
|
||||||
>
|
>
|
||||||
<ConfigProvider
|
<ConfigProvider
|
||||||
theme={{
|
theme={{
|
||||||
components: {
|
components: {
|
||||||
Card: {
|
Card: {
|
||||||
bodyPadding: 0,
|
bodyPadding: 0,
|
||||||
bodyPaddingSM: 0,
|
bodyPaddingSM: 0,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Outlet/>
|
<Outlet/>
|
||||||
</ConfigProvider>
|
</ConfigProvider>
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ import {PlusCircleFilled, SaveFilled} from '@ant-design/icons'
|
|||||||
import {
|
import {
|
||||||
Background,
|
Background,
|
||||||
BackgroundVariant,
|
BackgroundVariant,
|
||||||
|
type Connection,
|
||||||
Controls,
|
Controls,
|
||||||
type Edge,
|
getIncomers,
|
||||||
|
getOutgoers,
|
||||||
MiniMap,
|
MiniMap,
|
||||||
type Node,
|
type Node,
|
||||||
type NodeProps,
|
type NodeProps,
|
||||||
@@ -17,18 +19,16 @@ import {type JSX, useState} from 'react'
|
|||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import '@xyflow/react/dist/style.css'
|
import '@xyflow/react/dist/style.css'
|
||||||
import {amisRender, commonInfo, horizontalFormOptions} from '../../../util/amis.tsx'
|
import {amisRender, commonInfo, horizontalFormOptions} from '../../../util/amis.tsx'
|
||||||
import StartNode from './node/StartNode.tsx'
|
|
||||||
import EndNode from './node/EndNode.tsx'
|
import EndNode from './node/EndNode.tsx'
|
||||||
import LlmNode from './node/LlmNode.tsx'
|
import LlmNode from './node/LlmNode.tsx'
|
||||||
|
import StartNode from './node/StartNode.tsx'
|
||||||
import {useDataStore} from './store/DataStore.ts'
|
import {useDataStore} from './store/DataStore.ts'
|
||||||
import {useFlowStore} from './store/FlowStore.ts'
|
import {useFlowStore} from './store/FlowStore.ts'
|
||||||
|
|
||||||
const FlowableDiv = styled.div`
|
const FlowableDiv = styled.div`
|
||||||
height: 93vh;
|
height: 92vh;
|
||||||
|
|
||||||
.toolbar {
|
.toolbar {
|
||||||
z-index: 999;
|
|
||||||
position: absolute;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.node-card {
|
.node-card {
|
||||||
@@ -40,22 +40,6 @@ const FlowableDiv = styled.div`
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const initialNodes: Node[] = [
|
|
||||||
{
|
|
||||||
id: 'BMFP3Eov94',
|
|
||||||
type: 'start-amis-node',
|
|
||||||
position: {x: 10, y: 100},
|
|
||||||
data: {},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'PYK8LjduQ1',
|
|
||||||
type: 'end-amis-node',
|
|
||||||
position: {x: 500, y: 100},
|
|
||||||
data: {},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
const initialEdges: Edge[] = []
|
|
||||||
|
|
||||||
function FlowEditor() {
|
function FlowEditor() {
|
||||||
const [messageApi, contextHolder] = message.useMessage()
|
const [messageApi, contextHolder] = message.useMessage()
|
||||||
const [nodeDef] = useState<{
|
const [nodeDef] = useState<{
|
||||||
@@ -81,9 +65,10 @@ function FlowEditor() {
|
|||||||
])
|
])
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
|
|
||||||
const {getData, getDataById, setDataById} = useDataStore()
|
const {data, setData, getDataById, setDataById} = useDataStore()
|
||||||
const {
|
const {
|
||||||
nodes,
|
nodes,
|
||||||
|
getNodeById,
|
||||||
addNode,
|
addNode,
|
||||||
removeNode,
|
removeNode,
|
||||||
setNodes,
|
setNodes,
|
||||||
@@ -155,7 +140,7 @@ function FlowEditor() {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
getDataById(id),
|
getDataById(id),
|
||||||
),
|
),
|
||||||
@@ -164,7 +149,141 @@ function FlowEditor() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const checkNode = (type: string) => {
|
||||||
|
if (isEqual(type, 'start-amis-node') && findIdx(nodes, (node: Node) => isEqual(type, node.type)) > -1) {
|
||||||
|
throw new Error('只能存在1个开始节点')
|
||||||
|
}
|
||||||
|
if (isEqual(type, 'end-amis-node') && findIdx(nodes, (node: Node) => isEqual(type, node.type)) > -1) {
|
||||||
|
throw new Error('只能存在1个结束节点')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkConnection = (connection: Connection) => {
|
||||||
|
let sourceNode = getNodeById(connection.source)
|
||||||
|
if (!sourceNode) {
|
||||||
|
throw new Error('连线起始节点未找到')
|
||||||
|
}
|
||||||
|
let targetNode = getNodeById(connection.target)
|
||||||
|
if (!targetNode) {
|
||||||
|
throw new Error('连线目标节点未找到')
|
||||||
|
}
|
||||||
|
console.log(sourceNode, targetNode, connection)
|
||||||
|
// 禁止短路整个流程
|
||||||
|
if (isEqual('start-amis-node', sourceNode.type) && isEqual('end-amis-node', targetNode.type)) {
|
||||||
|
throw new Error('开始节点不能直连结束节点')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 禁止流程出现环,必须是有向无环图
|
||||||
|
const hasCycle = (node: Node, visited = new Set()) => {
|
||||||
|
if (visited.has(node.id)) return false
|
||||||
|
visited.add(node.id)
|
||||||
|
for (const outgoer of getOutgoers(node, nodes, edges)) {
|
||||||
|
if (isEqual(outgoer.id, sourceNode?.id)) return true
|
||||||
|
if (hasCycle(outgoer, visited)) return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isEqual(sourceNode.id, targetNode.id)) {
|
||||||
|
throw new Error('节点不能直连自身')
|
||||||
|
} else if (hasCycle(targetNode)) {
|
||||||
|
throw new Error('禁止流程循环')
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasShortcut = (node: Node, visited = new Set()) => {
|
||||||
|
if (visited.has(node.id)) return false
|
||||||
|
visited.add(node.id)
|
||||||
|
for (const incomer of getIncomers(node, nodes, edges)) {
|
||||||
|
if (isEqual(incomer.id, sourceNode?.id)) return true
|
||||||
|
if (hasShortcut(incomer, visited)) return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(getIncomers(targetNode, nodes, edges))
|
||||||
|
}
|
||||||
|
|
||||||
useMount(() => {
|
useMount(() => {
|
||||||
|
// language=JSON
|
||||||
|
let initialData = JSON.parse(`{
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"id": "BMFP3Eov94",
|
||||||
|
"type": "start-amis-node",
|
||||||
|
"position": {
|
||||||
|
"x": 10,
|
||||||
|
"y": 100
|
||||||
|
},
|
||||||
|
"data": {},
|
||||||
|
"measured": {
|
||||||
|
"width": 256,
|
||||||
|
"height": 83
|
||||||
|
},
|
||||||
|
"selected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "PYK8LjduQ1",
|
||||||
|
"type": "end-amis-node",
|
||||||
|
"position": {
|
||||||
|
"x": 654,
|
||||||
|
"y": 332
|
||||||
|
},
|
||||||
|
"data": {},
|
||||||
|
"measured": {
|
||||||
|
"width": 256,
|
||||||
|
"height": 83
|
||||||
|
},
|
||||||
|
"selected": false,
|
||||||
|
"dragging": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "nCm-ij5I6o",
|
||||||
|
"type": "llm-amis-node",
|
||||||
|
"position": {
|
||||||
|
"x": 318,
|
||||||
|
"y": 208
|
||||||
|
},
|
||||||
|
"data": {},
|
||||||
|
"measured": {
|
||||||
|
"width": 256,
|
||||||
|
"height": 83
|
||||||
|
},
|
||||||
|
"selected": true,
|
||||||
|
"dragging": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"edges": [
|
||||||
|
{
|
||||||
|
"source": "BMFP3Eov94",
|
||||||
|
"target": "nCm-ij5I6o",
|
||||||
|
"id": "xy-edge__BMFP3Eov94-nCm-ij5I6o"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"data": {
|
||||||
|
"BMFP3Eov94": {
|
||||||
|
"inputs": {
|
||||||
|
"文件名": {
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
"文件描述": {
|
||||||
|
"type": "text",
|
||||||
|
"description": "文件描述"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nCm-ij5I6o": {
|
||||||
|
"model": "qwen3",
|
||||||
|
"outputs": {
|
||||||
|
"text": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systemPrompt": "你是个沙雕"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
let initialNodes = initialData['nodes'] ?? []
|
||||||
|
let initialEdges = initialData['edges'] ?? []
|
||||||
|
|
||||||
|
let initialNodeData = initialData['data'] ?? {}
|
||||||
|
setData(initialNodeData)
|
||||||
|
|
||||||
for (let node of initialNodes) {
|
for (let node of initialNodes) {
|
||||||
node.data = {
|
node.data = {
|
||||||
getDataById,
|
getDataById,
|
||||||
@@ -181,7 +300,10 @@ function FlowEditor() {
|
|||||||
<FlowableDiv>
|
<FlowableDiv>
|
||||||
{contextHolder}
|
{contextHolder}
|
||||||
<Space className="toolbar">
|
<Space className="toolbar">
|
||||||
<Button type="primary" onClick={() => console.log(JSON.stringify(getData()))}>
|
<Button type="primary" onClick={() => {
|
||||||
|
let saveData = {nodes, edges, data}
|
||||||
|
console.log(JSON.stringify(saveData, null, 2))
|
||||||
|
}}>
|
||||||
<SaveFilled/>
|
<SaveFilled/>
|
||||||
保存
|
保存
|
||||||
</Button>
|
</Button>
|
||||||
@@ -189,26 +311,23 @@ function FlowEditor() {
|
|||||||
menu={{
|
menu={{
|
||||||
items: nodeDef.map(def => ({key: def.key, label: def.name})),
|
items: nodeDef.map(def => ({key: def.key, label: def.name})),
|
||||||
onClick: ({key}) => {
|
onClick: ({key}) => {
|
||||||
if (isEqual(key, 'start-amis-node') && findIdx(nodes, (node: Node) => isEqual(key, node.type)) > -1) {
|
try {
|
||||||
messageApi.error('只能存在1个开始节点')
|
checkNode(key)
|
||||||
return
|
addNode({
|
||||||
|
id: randomId(10),
|
||||||
|
type: key,
|
||||||
|
position: {x: 100, y: 100},
|
||||||
|
data: {
|
||||||
|
getDataById,
|
||||||
|
setDataById,
|
||||||
|
removeNode,
|
||||||
|
editNode,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
// @ts-ignore
|
||||||
|
messageApi.error(e.message)
|
||||||
}
|
}
|
||||||
if (isEqual(key, 'end-amis-node') && findIdx(nodes, (node: Node) => isEqual(key, node.type)) > -1) {
|
|
||||||
messageApi.error('只能存在1个结束节点')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
addNode({
|
|
||||||
id: randomId(10),
|
|
||||||
type: key,
|
|
||||||
position: {x: 100, y: 100},
|
|
||||||
data: {
|
|
||||||
getDataById,
|
|
||||||
setDataById,
|
|
||||||
removeNode,
|
|
||||||
editNode,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -233,7 +352,15 @@ function FlowEditor() {
|
|||||||
edges={edges}
|
edges={edges}
|
||||||
onNodesChange={onNodesChange}
|
onNodesChange={onNodesChange}
|
||||||
onEdgesChange={onEdgesChange}
|
onEdgesChange={onEdgesChange}
|
||||||
onConnect={onConnect}
|
onConnect={(connection) => {
|
||||||
|
try {
|
||||||
|
checkConnection(connection)
|
||||||
|
onConnect(connection)
|
||||||
|
} catch (e) {
|
||||||
|
// @ts-ignore
|
||||||
|
messageApi.error(e.message)
|
||||||
|
}
|
||||||
|
}}
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
nodeTypes={arrToMap(
|
nodeTypes={arrToMap(
|
||||||
nodeDef.map(def => def.key),
|
nodeDef.map(def => def.key),
|
||||||
|
|||||||
@@ -1,12 +1,59 @@
|
|||||||
|
import {DeleteFilled, EditFilled} from '@ant-design/icons'
|
||||||
import {Handle, type NodeProps, Position} from '@xyflow/react'
|
import {Handle, type NodeProps, Position} from '@xyflow/react'
|
||||||
import type {Schema} from 'amis'
|
import type {Schema} from 'amis'
|
||||||
import {Card, Dropdown} from 'antd'
|
import {Card, Dropdown} from 'antd'
|
||||||
import {DeleteFilled, EditFilled} from '@ant-design/icons'
|
|
||||||
import {isEmpty, isEqual} from 'licia'
|
import {isEmpty, isEqual} from 'licia'
|
||||||
import type {JSX} from 'react'
|
import type {JSX} from 'react'
|
||||||
|
import {horizontalFormOptions} from '../../../../util/amis.tsx'
|
||||||
|
|
||||||
export type AmisNodeType = 'normal' | 'start' | 'end'
|
export type AmisNodeType = 'normal' | 'start' | 'end'
|
||||||
|
|
||||||
|
export function outputsFormColumns(editable: boolean = false, preload?: any): Schema[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
disabled: !editable,
|
||||||
|
type: 'input-kvs',
|
||||||
|
name: 'outputs',
|
||||||
|
label: '输出变量',
|
||||||
|
value: preload,
|
||||||
|
addButtonText: '新增输出',
|
||||||
|
draggable: false,
|
||||||
|
keyItem: {
|
||||||
|
...horizontalFormOptions(),
|
||||||
|
label: '参数名称',
|
||||||
|
},
|
||||||
|
valueItems: [
|
||||||
|
{
|
||||||
|
...horizontalFormOptions(),
|
||||||
|
type: 'select',
|
||||||
|
name: 'type',
|
||||||
|
label: '参数',
|
||||||
|
required: true,
|
||||||
|
selectFirst: true,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: '文本',
|
||||||
|
value: 'string',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '数字',
|
||||||
|
value: 'number',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '文本数组',
|
||||||
|
value: 'array-string',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '对象数组',
|
||||||
|
value: 'array-object',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
const AmisNode = (
|
const AmisNode = (
|
||||||
props: NodeProps,
|
props: NodeProps,
|
||||||
type: AmisNodeType,
|
type: AmisNodeType,
|
||||||
@@ -67,10 +114,10 @@ const AmisNode = (
|
|||||||
placeholder: nodeDescription,
|
placeholder: nodeDescription,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'divider'
|
type: 'divider',
|
||||||
},
|
},
|
||||||
...(columnSchema ?? [])
|
...(columnSchema ?? []),
|
||||||
]
|
],
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
case 'remove':
|
case 'remove':
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import type {NodeProps} from '@xyflow/react'
|
import type {NodeProps} from '@xyflow/react'
|
||||||
import AmisNode from './AmisNode.tsx'
|
import AmisNode, {outputsFormColumns} from './AmisNode.tsx'
|
||||||
import {horizontalFormOptions} from '../../../../util/amis.tsx'
|
|
||||||
|
|
||||||
const EndNode = (props: NodeProps) => AmisNode(
|
const EndNode = (props: NodeProps) => AmisNode(
|
||||||
props,
|
props,
|
||||||
@@ -8,30 +7,7 @@ const EndNode = (props: NodeProps) => AmisNode(
|
|||||||
'结束节点',
|
'结束节点',
|
||||||
'定义输出变量',
|
'定义输出变量',
|
||||||
undefined,
|
undefined,
|
||||||
[
|
outputsFormColumns(true),
|
||||||
{
|
|
||||||
type: 'input-kvs',
|
|
||||||
name: 'outputVariables',
|
|
||||||
label: '输出变量',
|
|
||||||
addButtonText: '新增输出',
|
|
||||||
draggable: false,
|
|
||||||
keyItem: {
|
|
||||||
...horizontalFormOptions(),
|
|
||||||
label: '参数名称',
|
|
||||||
},
|
|
||||||
valueItems: [
|
|
||||||
{
|
|
||||||
...horizontalFormOptions(),
|
|
||||||
type: 'select',
|
|
||||||
name: 'type',
|
|
||||||
label: '参数',
|
|
||||||
required: true,
|
|
||||||
selectFirst: true,
|
|
||||||
options: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
export default EndNode
|
export default EndNode
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import type {NodeProps} from '@xyflow/react'
|
import type {NodeProps} from '@xyflow/react'
|
||||||
import AmisNode from './AmisNode.tsx'
|
import AmisNode, {outputsFormColumns} from './AmisNode.tsx'
|
||||||
|
|
||||||
const LlmNode = (props: NodeProps) => AmisNode(
|
const LlmNode = (props: NodeProps) => AmisNode(
|
||||||
props,
|
props,
|
||||||
@@ -31,6 +31,10 @@ const LlmNode = (props: NodeProps) => AmisNode(
|
|||||||
label: '系统提示词',
|
label: '系统提示词',
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: 'divider',
|
||||||
|
},
|
||||||
|
...outputsFormColumns(false, {text: {type: 'string'}}),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type {NodeProps} from '@xyflow/react'
|
import type {NodeProps} from '@xyflow/react'
|
||||||
import AmisNode from './AmisNode.tsx'
|
|
||||||
import {horizontalFormOptions} from '../../../../util/amis.tsx'
|
import {horizontalFormOptions} from '../../../../util/amis.tsx'
|
||||||
|
import AmisNode from './AmisNode.tsx'
|
||||||
|
|
||||||
const StartNode = (props: NodeProps) => AmisNode(
|
const StartNode = (props: NodeProps) => AmisNode(
|
||||||
props,
|
props,
|
||||||
@@ -11,7 +11,7 @@ const StartNode = (props: NodeProps) => AmisNode(
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
type: 'input-kvs',
|
type: 'input-kvs',
|
||||||
name: 'inputVariables',
|
name: 'inputs',
|
||||||
label: '输入变量',
|
label: '输入变量',
|
||||||
addButtonText: '新增入参',
|
addButtonText: '新增入参',
|
||||||
draggable: false,
|
draggable: false,
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ export const useDataStore = create<{
|
|||||||
}>((set, get) => ({
|
}>((set, get) => ({
|
||||||
data: {},
|
data: {},
|
||||||
getData: () => get().data,
|
getData: () => get().data,
|
||||||
setData: (data) => set(data),
|
setData: (data) => set({
|
||||||
|
data: data
|
||||||
|
}),
|
||||||
getDataById: id => get().data[id],
|
getDataById: id => get().data[id],
|
||||||
setDataById: (id, data) => {
|
setDataById: (id, data) => {
|
||||||
let updateData = get().data
|
let updateData = get().data
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import {create} from 'zustand/react'
|
|
||||||
import {
|
import {
|
||||||
addEdge,
|
addEdge,
|
||||||
applyEdgeChanges,
|
applyEdgeChanges,
|
||||||
@@ -7,13 +6,15 @@ import {
|
|||||||
type Node,
|
type Node,
|
||||||
type OnConnect,
|
type OnConnect,
|
||||||
type OnEdgesChange,
|
type OnEdgesChange,
|
||||||
type OnNodesChange
|
type OnNodesChange,
|
||||||
} from '@xyflow/react'
|
} from '@xyflow/react'
|
||||||
import {filter, isEqual} from 'licia'
|
import {filter, find, isEqual} from 'licia'
|
||||||
|
import {create} from 'zustand/react'
|
||||||
|
|
||||||
export const useFlowStore = create<{
|
export const useFlowStore = create<{
|
||||||
nodes: Node[],
|
nodes: Node[],
|
||||||
onNodesChange: OnNodesChange,
|
onNodesChange: OnNodesChange,
|
||||||
|
getNodeById: (id: string) => Node | undefined,
|
||||||
addNode: (node: Node) => void,
|
addNode: (node: Node) => void,
|
||||||
removeNode: (id: string) => void,
|
removeNode: (id: string) => void,
|
||||||
setNodes: (nodes: Node[]) => void,
|
setNodes: (nodes: Node[]) => void,
|
||||||
@@ -30,6 +31,7 @@ export const useFlowStore = create<{
|
|||||||
nodes: applyNodeChanges(changes, get().nodes),
|
nodes: applyNodeChanges(changes, get().nodes),
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
getNodeById: (id: string) => find(get().nodes, node => isEqual(node.id, id)),
|
||||||
addNode: node => set({nodes: get().nodes.concat(node)}),
|
addNode: node => set({nodes: get().nodes.concat(node)}),
|
||||||
removeNode: id => {
|
removeNode: id => {
|
||||||
set({
|
set({
|
||||||
|
|||||||
Reference in New Issue
Block a user