feat(web): 完成循环节点的基本配置
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
import {CopyFilled, DeleteFilled, EditFilled} from '@ant-design/icons'
|
||||
import {type Edge, Handle, type Node, type NodeProps, NodeToolbar, Position} from '@xyflow/react'
|
||||
import type {Schema} from 'amis'
|
||||
import {Button, Card, Drawer, Space, Tooltip} from 'antd'
|
||||
import {type JSX, useCallback, useState} from 'react'
|
||||
import {type Edge, Handle, type Node, type NodeProps, NodeResizeControl, NodeToolbar, Position} from '@xyflow/react'
|
||||
import {type ClassName, classnames, type Schema} from 'amis'
|
||||
import {Button, Drawer, Space, Tooltip} from 'antd'
|
||||
import {type CSSProperties, type JSX, useCallback, useState} from 'react'
|
||||
import styled from 'styled-components'
|
||||
import {amisRender, commonInfo, horizontalFormOptions} from '../../../util/amis.tsx'
|
||||
import {generateAllIncomerOutputVariablesFormOptions} from '../Helper.tsx'
|
||||
@@ -95,20 +95,16 @@ export function outputsFormColumns(editable: boolean = false, required: boolean
|
||||
}
|
||||
|
||||
type AmisNodeProps = {
|
||||
className: ClassName,
|
||||
style?: CSSProperties,
|
||||
nodeProps: NodeProps
|
||||
extraNodeDescription?: JSX.Element
|
||||
handler: JSX.Element
|
||||
columnSchema?: () => Schema[]
|
||||
resize?: { minWidth: number, minHeight: number }
|
||||
}
|
||||
|
||||
const AmisNodeContainerDiv = styled.div`
|
||||
.ant-card {
|
||||
.ant-card-actions {
|
||||
& > li {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const StartNodeHandler = () => {
|
||||
@@ -128,11 +124,18 @@ export const NormalNodeHandler = () => {
|
||||
)
|
||||
}
|
||||
|
||||
export const nodeClassName = (name: string) => {
|
||||
return `flow-node flow-node-${name}`
|
||||
}
|
||||
|
||||
const AmisNode: (props: AmisNodeProps) => JSX.Element = ({
|
||||
className,
|
||||
style,
|
||||
nodeProps,
|
||||
extraNodeDescription,
|
||||
handler,
|
||||
columnSchema,
|
||||
resize,
|
||||
}) => {
|
||||
const {removeNode} = useFlowStore()
|
||||
const {getDataById, setDataById, removeDataById} = useDataStore()
|
||||
@@ -236,7 +239,7 @@ const AmisNode: (props: AmisNodeProps) => JSX.Element = ({
|
||||
removeDataById(id)
|
||||
}, [])
|
||||
return (
|
||||
<AmisNodeContainerDiv className="w-64">
|
||||
<AmisNodeContainerDiv className={classnames(className, 'w-64')} style={style}>
|
||||
<Drawer
|
||||
title="节点编辑"
|
||||
open={editDrawerOpen}
|
||||
@@ -278,17 +281,27 @@ const AmisNode: (props: AmisNodeProps) => JSX.Element = ({
|
||||
</Tooltip>
|
||||
</Space>
|
||||
</NodeToolbar>
|
||||
<Card
|
||||
className="node-card"
|
||||
title={nodeName}
|
||||
extra={<span className="text-gray-300 text-xs">{id}</span>}
|
||||
size="small"
|
||||
>
|
||||
<div className="card-description p-2 text-secondary text-sm">
|
||||
{nodeDescription}
|
||||
{extraNodeDescription}
|
||||
<div className="node-card h-full flex flex-col bg-white rounded-md border border-gray-100 border-solid">
|
||||
<div
|
||||
className="node-card-header items-center flex justify-between p-2 border-t-0 border-l-0 border-r-0 border-b border-gray-100 border-solid">
|
||||
<span className="font-bold">{nodeName}</span>
|
||||
<span className="text-gray-300 text-sm">{id}</span>
|
||||
</div>
|
||||
</Card>
|
||||
<div className="node-card-description flex flex-col flex-1 p-2 text-secondary text-sm">
|
||||
<div className="node-card-description-node">
|
||||
{nodeDescription}
|
||||
</div>
|
||||
<div className="node-card-description-extra flex-1 mt-1">
|
||||
{extraNodeDescription}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{resize ? <>
|
||||
<NodeResizeControl
|
||||
minWidth={resize.minWidth}
|
||||
minHeight={resize.minHeight}
|
||||
/>
|
||||
</> : undefined}
|
||||
{handler}
|
||||
</AmisNodeContainerDiv>
|
||||
)
|
||||
|
||||
@@ -4,7 +4,7 @@ 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, {inputsFormColumns, NormalNodeHandler, outputsFormColumns} from './AmisNode.tsx'
|
||||
import AmisNode, {inputsFormColumns, nodeClassName, NormalNodeHandler, outputsFormColumns} from './AmisNode.tsx'
|
||||
|
||||
const languageMap: Record<string, string> = {
|
||||
'javascript': 'Javascript',
|
||||
@@ -62,6 +62,7 @@ const CodeNode = (props: NodeProps) => {
|
||||
], [props.id])
|
||||
return (
|
||||
<AmisNode
|
||||
className={nodeClassName('code')}
|
||||
nodeProps={props}
|
||||
extraNodeDescription={
|
||||
nodeData?.type
|
||||
|
||||
@@ -4,7 +4,7 @@ import {commonInfo} from '../../../util/amis.tsx'
|
||||
import {useContextStore} from '../store/ContextStore.ts'
|
||||
import {useDataStore} from '../store/DataStore.ts'
|
||||
import {useFlowStore} from '../store/FlowStore.ts'
|
||||
import AmisNode, {inputsFormColumns, NormalNodeHandler, outputsFormColumns} from './AmisNode.tsx'
|
||||
import AmisNode, {inputsFormColumns, nodeClassName, NormalNodeHandler, outputsFormColumns} from './AmisNode.tsx'
|
||||
|
||||
const KnowledgeNode = (props: NodeProps) => {
|
||||
const {getNodes, getEdges} = useFlowStore()
|
||||
@@ -79,6 +79,7 @@ const KnowledgeNode = (props: NodeProps) => {
|
||||
], [props.id])
|
||||
return (
|
||||
<AmisNode
|
||||
className={nodeClassName('knowledge')}
|
||||
nodeProps={props}
|
||||
columnSchema={columnsSchema}
|
||||
handler={<NormalNodeHandler/>}
|
||||
|
||||
@@ -4,7 +4,7 @@ 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, {inputsFormColumns, NormalNodeHandler, outputsFormColumns} from './AmisNode.tsx'
|
||||
import AmisNode, {inputsFormColumns, nodeClassName, NormalNodeHandler, outputsFormColumns} from './AmisNode.tsx'
|
||||
|
||||
const modelMap: Record<string, string> = {
|
||||
qwen3: 'Qwen3',
|
||||
@@ -57,6 +57,7 @@ const LlmNode = (props: NodeProps) => {
|
||||
], [props.id])
|
||||
return (
|
||||
<AmisNode
|
||||
className={nodeClassName('llm')}
|
||||
nodeProps={props}
|
||||
extraNodeDescription={
|
||||
nodeData?.model
|
||||
|
||||
46
service-web/client/src/components/flow/node/LoopNode.tsx
Normal file
46
service-web/client/src/components/flow/node/LoopNode.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import {Background, BackgroundVariant, type NodeProps} from '@xyflow/react'
|
||||
import {classnames} from 'amis'
|
||||
import React from 'react'
|
||||
import {flowBackgroundColor, flowDotColor} from '../types.ts'
|
||||
import AmisNode, {nodeClassName, NormalNodeHandler} from './AmisNode.tsx'
|
||||
|
||||
const LoopNode = (props: NodeProps) => {
|
||||
return (
|
||||
<AmisNode
|
||||
className={classnames('w-full', 'h-full', nodeClassName('loop'))}
|
||||
style={{
|
||||
minWidth: '256px',
|
||||
minHeight: '110px'
|
||||
}}
|
||||
nodeProps={props}
|
||||
extraNodeDescription={
|
||||
<div
|
||||
className="nodrag relative h-full w-full"
|
||||
style={{
|
||||
minHeight: '8rem',
|
||||
}}
|
||||
>
|
||||
<Background
|
||||
id={`loop-background-${props.id}`}
|
||||
className="rounded-xl"
|
||||
variant={BackgroundVariant.Cross}
|
||||
gap={20}
|
||||
size={3}
|
||||
style={{
|
||||
zIndex: 0,
|
||||
}}
|
||||
color={flowDotColor}
|
||||
bgColor={flowBackgroundColor}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
handler={<NormalNodeHandler/>}
|
||||
resize={{
|
||||
minWidth: 256,
|
||||
minHeight: 208,
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default React.memo(LoopNode)
|
||||
@@ -4,7 +4,7 @@ import {generateAllIncomerOutputVariablesFormOptions} from '../Helper.tsx'
|
||||
import {useContextStore} from '../store/ContextStore.ts'
|
||||
import {useDataStore} from '../store/DataStore.ts'
|
||||
import {useFlowStore} from '../store/FlowStore.ts'
|
||||
import AmisNode, {EndNodeHandler} from './AmisNode.tsx'
|
||||
import AmisNode, {EndNodeHandler, nodeClassName} from './AmisNode.tsx'
|
||||
|
||||
const OutputNode = (props: NodeProps) => {
|
||||
const {getNodes, getEdges} = useFlowStore()
|
||||
@@ -33,6 +33,7 @@ const OutputNode = (props: NodeProps) => {
|
||||
|
||||
return (
|
||||
<AmisNode
|
||||
className={nodeClassName('output')}
|
||||
nodeProps={props}
|
||||
columnSchema={columnsSchema}
|
||||
handler={<EndNodeHandler/>}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {Handle, type NodeProps, Position} from '@xyflow/react'
|
||||
import {Tag} from 'antd'
|
||||
import React from 'react'
|
||||
import AmisNode from './AmisNode.tsx'
|
||||
import AmisNode, {nodeClassName} from './AmisNode.tsx'
|
||||
|
||||
const cases = [
|
||||
{
|
||||
@@ -18,6 +18,7 @@ const cases = [
|
||||
const SwitchNode = (props: NodeProps) => {
|
||||
return (
|
||||
<AmisNode
|
||||
className={nodeClassName('switch')}
|
||||
nodeProps={props}
|
||||
extraNodeDescription={
|
||||
<div className="mt-2">
|
||||
|
||||
@@ -4,7 +4,7 @@ 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, {inputsFormColumns, NormalNodeHandler, outputsFormColumns} from './AmisNode.tsx'
|
||||
import AmisNode, {inputsFormColumns, nodeClassName, NormalNodeHandler, outputsFormColumns} from './AmisNode.tsx'
|
||||
|
||||
const typeMap: Record<string, string> = {
|
||||
default: '默认',
|
||||
@@ -75,6 +75,7 @@ const TemplateNode = (props: NodeProps) => {
|
||||
|
||||
return (
|
||||
<AmisNode
|
||||
className={nodeClassName('template')}
|
||||
nodeProps={props}
|
||||
extraNodeDescription={
|
||||
nodeData?.type
|
||||
|
||||
Reference in New Issue
Block a user