feat(web): 增加模板节点
This commit is contained in:
@@ -2,14 +2,12 @@ import {CopyFilled, DeleteFilled, EditFilled} from '@ant-design/icons'
|
||||
import {type Edge, Handle, type Node, type NodeProps, Position} from '@xyflow/react'
|
||||
import type {Schema} from 'amis'
|
||||
import {Button, Card, Drawer} from 'antd'
|
||||
import {has, isEmpty} from 'licia'
|
||||
import {type JSX, useCallback, useState} from 'react'
|
||||
import styled from 'styled-components'
|
||||
import {amisRender, commonInfo, horizontalFormOptions} from '../../../util/amis.tsx'
|
||||
import {getAllIncomerNodeById} from '../Helper.tsx'
|
||||
import {generateAllIncomerOutputVariablesFormOptions} from '../Helper.tsx'
|
||||
import {useDataStore} from '../store/DataStore.ts'
|
||||
import {useFlowStore} from '../store/FlowStore.ts'
|
||||
import type {InputFormOptions, InputFormOptionsGroup} from '../types.ts'
|
||||
|
||||
export function inputsFormColumns(
|
||||
nodeId: string,
|
||||
@@ -18,41 +16,6 @@ export function inputsFormColumns(
|
||||
edges: Edge[],
|
||||
data: any,
|
||||
): Schema[] {
|
||||
let inputSchemaVariables: InputFormOptions[] = Object.keys(inputSchema).map(key => ({
|
||||
label: `${key} (${inputSchema[key]?.label ?? ''})`,
|
||||
value: key,
|
||||
}))
|
||||
|
||||
let incomerIds = getAllIncomerNodeById(nodeId, nodes, edges)
|
||||
let incomerVariables: InputFormOptionsGroup[] = []
|
||||
for (const incomerId of incomerIds) {
|
||||
let nodeData = data[incomerId] ?? {}
|
||||
let group = incomerId
|
||||
if (has(nodeData, 'node') && has(nodeData.node, 'name')) {
|
||||
group = `${nodeData.node.name} ${incomerId}`
|
||||
}
|
||||
if (has(nodeData, 'outputs')) {
|
||||
let outputs = nodeData?.outputs ?? []
|
||||
incomerVariables.push({
|
||||
group: group,
|
||||
variables: Object.keys(outputs).map(key => ({
|
||||
value: `${incomerId}.${key}`,
|
||||
label: key,
|
||||
})),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let inputVariables = [
|
||||
...(isEmpty(inputSchemaVariables) ? [] : [
|
||||
{
|
||||
group: '流程入参',
|
||||
variables: inputSchemaVariables,
|
||||
},
|
||||
]),
|
||||
...incomerVariables,
|
||||
]
|
||||
|
||||
return [
|
||||
{
|
||||
type: 'input-kvs',
|
||||
@@ -72,12 +35,13 @@ export function inputsFormColumns(
|
||||
label: '变量',
|
||||
required: true,
|
||||
selectMode: 'group',
|
||||
options: [
|
||||
...inputVariables.map(item => ({
|
||||
label: item.group,
|
||||
children: item.variables,
|
||||
})),
|
||||
],
|
||||
options: generateAllIncomerOutputVariablesFormOptions(
|
||||
nodeId,
|
||||
inputSchema,
|
||||
nodes,
|
||||
edges,
|
||||
data,
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -1,59 +1,31 @@
|
||||
import type {NodeProps} from '@xyflow/react'
|
||||
import {Tag} from 'antd'
|
||||
import React, {useCallback} from 'react'
|
||||
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, inputsFormColumns} from './AmisNode.tsx'
|
||||
|
||||
const typeMap: Record<string, string> = {
|
||||
markdown: 'Markdown',
|
||||
json: 'JSON',
|
||||
'template-markdown': 'Markdown 模板',
|
||||
'template-rich-text': '富文本模板',
|
||||
}
|
||||
import AmisNode, {EndNodeHandler} from './AmisNode.tsx'
|
||||
|
||||
const OutputNode = (props: NodeProps) => {
|
||||
const {getNodes, getEdges} = useFlowStore()
|
||||
const {getData, getDataById} = useDataStore()
|
||||
const {getData} = useDataStore()
|
||||
const {getInputSchema} = useContextStore()
|
||||
|
||||
const nodeData = getDataById(props.id)
|
||||
|
||||
const columnsSchema = useCallback(
|
||||
() => [
|
||||
...inputsFormColumns(props.id, getInputSchema(), getNodes(), getEdges(), getData()),
|
||||
{
|
||||
type: 'divider',
|
||||
},
|
||||
{
|
||||
type: 'select',
|
||||
name: 'type',
|
||||
label: '输出类型',
|
||||
name: 'output',
|
||||
label: '输出变量',
|
||||
required: true,
|
||||
selectFirst: true,
|
||||
options: Object.keys(typeMap).map(key => ({label: typeMap[key], value: key})),
|
||||
},
|
||||
{
|
||||
visibleOn: 'type === \'template-markdown\'',
|
||||
type: 'editor',
|
||||
required: true,
|
||||
label: '模板内容',
|
||||
name: 'template',
|
||||
language: 'markdown',
|
||||
options: {
|
||||
wordWrap: 'bounded',
|
||||
},
|
||||
},
|
||||
{
|
||||
visibleOn: 'type === \'template-rich-text\'',
|
||||
type: 'input-rich-text',
|
||||
required: true,
|
||||
name: 'template',
|
||||
label: '模板内容',
|
||||
options: {
|
||||
min_height: 500,
|
||||
},
|
||||
selectMode: 'group',
|
||||
options: generateAllIncomerOutputVariablesFormOptions(
|
||||
props.id,
|
||||
getInputSchema(),
|
||||
getNodes(),
|
||||
getEdges(),
|
||||
getData(),
|
||||
),
|
||||
},
|
||||
],
|
||||
[props.id],
|
||||
@@ -62,14 +34,6 @@ const OutputNode = (props: NodeProps) => {
|
||||
return (
|
||||
<AmisNode
|
||||
nodeProps={props}
|
||||
extraNodeDescription={
|
||||
nodeData?.type
|
||||
? <div className="mt-2 flex justify-between">
|
||||
<span>输出类型</span>
|
||||
<Tag className="m-0" color="blue">{typeMap[nodeData.type]}</Tag>
|
||||
</div>
|
||||
: <></>
|
||||
}
|
||||
columnSchema={columnsSchema}
|
||||
handler={<EndNodeHandler/>}
|
||||
/>
|
||||
|
||||
79
service-web/client/src/components/flow/node/TemplateNode.tsx
Normal file
79
service-web/client/src/components/flow/node/TemplateNode.tsx
Normal file
@@ -0,0 +1,79 @@
|
||||
import type {NodeProps} from '@xyflow/react'
|
||||
import {Tag} from 'antd'
|
||||
import React, {useCallback} 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'
|
||||
|
||||
const typeMap: Record<string, string> = {
|
||||
default: '默认',
|
||||
json: 'JSON',
|
||||
'template-markdown': 'Markdown',
|
||||
'template-rich-text': '富文本',
|
||||
}
|
||||
|
||||
const TemplateNode = (props: NodeProps) => {
|
||||
const {getNodes, getEdges} = useFlowStore()
|
||||
const {getData, getDataById} = useDataStore()
|
||||
const {getInputSchema} = useContextStore()
|
||||
|
||||
const nodeData = getDataById(props.id)
|
||||
|
||||
const columnsSchema = useCallback(
|
||||
() => [
|
||||
...inputsFormColumns(props.id, getInputSchema(), getNodes(), getEdges(), getData()),
|
||||
{
|
||||
type: 'divider',
|
||||
},
|
||||
{
|
||||
type: 'select',
|
||||
name: 'type',
|
||||
label: '模板类型',
|
||||
required: true,
|
||||
selectFirst: true,
|
||||
options: Object.keys(typeMap).map(key => ({label: typeMap[key], value: key})),
|
||||
},
|
||||
{
|
||||
visibleOn: 'type === \'template-markdown\'',
|
||||
type: 'editor',
|
||||
required: true,
|
||||
label: '模板内容',
|
||||
name: 'template',
|
||||
language: 'markdown',
|
||||
options: {
|
||||
wordWrap: 'bounded',
|
||||
},
|
||||
},
|
||||
{
|
||||
visibleOn: 'type === \'template-rich-text\'',
|
||||
type: 'input-rich-text',
|
||||
required: true,
|
||||
name: 'template',
|
||||
label: '模板内容',
|
||||
options: {
|
||||
min_height: 500,
|
||||
},
|
||||
},
|
||||
],
|
||||
[props.id],
|
||||
)
|
||||
|
||||
return (
|
||||
<AmisNode
|
||||
nodeProps={props}
|
||||
extraNodeDescription={
|
||||
nodeData?.type
|
||||
? <div className="mt-2 flex justify-between">
|
||||
<span>模板类型</span>
|
||||
<Tag className="m-0" color="blue">{typeMap[nodeData.type]}</Tag>
|
||||
</div>
|
||||
: <></>
|
||||
}
|
||||
columnSchema={columnsSchema}
|
||||
handler={<EndNodeHandler/>}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default React.memo(TemplateNode)
|
||||
Reference in New Issue
Block a user