diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/manager/FlowNodeState.java b/flow-engine-framework/src/main/java/com/codingapi/flow/manager/FlowNodeState.java index 13a1ed79..4eb996ad 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/manager/FlowNodeState.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/manager/FlowNodeState.java @@ -5,6 +5,7 @@ import lombok.Getter; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import java.util.stream.Stream; @@ -31,7 +32,7 @@ public FlowNodeState(IFlowNode node) { this.branchNodeTypes.add(NodeType.PARALLEL_BRANCH.name()); } - public boolean isEndNode(){ + public boolean isEndNode() { return this.node.getType().equals(NodeType.END.name()); } @@ -65,8 +66,8 @@ public String getName() { } public List getFirstBlocks() { - List blocks = this.node.blocks(); - if (blocks != null && !blocks.isEmpty()) { + List blocks = this.node.blocks().stream().sorted(Comparator.comparingInt(IFlowNode::getOrder)).toList(); + if (!blocks.isEmpty()) { return Stream.of(blocks.get(0)).toList(); } return new ArrayList<>(); diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ConditionNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ConditionNode.java index 3a6865c8..58ee9183 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ConditionNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ConditionNode.java @@ -37,6 +37,7 @@ public void addDefaultBranch(int count){ List branches = new ArrayList<>(); for (int i=0;i branches = new ArrayList<>(); for (int i=0;i branches = new ArrayList<>(); for (int i=0;i=18", diff --git a/frontend/packages/flow-core/rstest.config.ts b/frontend/packages/flow-core/rstest.config.ts new file mode 100644 index 00000000..9057a186 --- /dev/null +++ b/frontend/packages/flow-core/rstest.config.ts @@ -0,0 +1,15 @@ +import {pluginReact} from '@rsbuild/plugin-react'; +import {defineConfig} from '@rstest/core'; +import {pluginSass} from "@rsbuild/plugin-sass"; +import * as path from "path"; + +export default defineConfig({ + testEnvironment: 'jsdom', + setupFiles: ['./rstest.setup.ts'], + plugins: [pluginReact(), pluginSass()], + resolve: { + alias: { + "@/": path.resolve(__dirname, "src"), + } + } +}); diff --git a/frontend/packages/flow-core/rstest.setup.ts b/frontend/packages/flow-core/rstest.setup.ts new file mode 100644 index 00000000..32b38ae2 --- /dev/null +++ b/frontend/packages/flow-core/rstest.setup.ts @@ -0,0 +1,4 @@ +import { expect } from '@rstest/core'; +import * as jestDomMatchers from '@testing-library/jest-dom/matchers'; + +expect.extend(jestDomMatchers); diff --git a/frontend/packages/flow-core/src/groovy.ts b/frontend/packages/flow-core/src/groovy.ts index 675b5ae8..b823e008 100644 --- a/frontend/packages/flow-core/src/groovy.ts +++ b/frontend/packages/flow-core/src/groovy.ts @@ -415,7 +415,7 @@ export class GroovyScriptConvertorUtil { */ public static updateScriptMeta(script: string, meta: string): string { const metaComment = `// ${SCRIPT_META} ${meta}`; - if (GroovyScriptConvertorUtil.getScriptTitle(script)) { + if (GroovyScriptConvertorUtil.getScriptMeta(script)) { return script.replace(new RegExp(`//\\s*${SCRIPT_META}\\s*.+`), metaComment); } else { return `${metaComment}\n${script}`; diff --git a/frontend/packages/flow-pc/flow-pc-design/tests/script/utils/convertor-utils.test.ts b/frontend/packages/flow-core/tests/groovy.test.ts similarity index 75% rename from frontend/packages/flow-pc/flow-pc-design/tests/script/utils/convertor-utils.test.ts rename to frontend/packages/flow-core/tests/groovy.test.ts index c3c85196..30505833 100644 --- a/frontend/packages/flow-pc/flow-pc-design/tests/script/utils/convertor-utils.test.ts +++ b/frontend/packages/flow-core/tests/groovy.test.ts @@ -1,5 +1,5 @@ import {describe, expect, it} from '@rstest/core'; -import {GroovyScriptConvertorUtil} from "@/components/script/utils/convertor"; +import {GroovyScriptConvertorUtil} from "@/groovy"; describe('GroovyScriptUtil', () => { @@ -54,7 +54,7 @@ def run(request){ }); - describe('getScriptMeta', () => { + describe('getScriptMeta1', () => { it('get groovy script meta', () => { const script = ` // @SCRIPT_TITLE 这是一个实例的标题 @@ -67,8 +67,21 @@ def run(request){ }); }); + describe('getScriptMeta2', () => { + it('get groovy script meta', () => { + const script = ` +// @CUSTOM_SCRIPT 自定义脚本,返回的数据为动作类型 +// @SCRIPT_META {"trigger":"PASS"} +def run(request){ + return 'SAVE'; +}` + const result = GroovyScriptConvertorUtil.getScriptMeta(script) + expect(result).toEqual(`{"trigger":"PASS"}`); + }); + }); - describe('updateScriptMeta', () => { + + describe('updateScriptMeta1', () => { it('update groovy script meta', () => { const script = ` // @SCRIPT_TITLE 这是一个实例的标题 @@ -82,4 +95,19 @@ def run(request){ expect(title).toEqual(`{name:"test"}`); }); }); + + describe('updateScriptMeta2', () => { + it('update groovy script meta', () => { + const script = ` +// @CUSTOM_SCRIPT 自定义脚本,返回的数据为动作类型 +// @SCRIPT_META {"trigger":"PASS"} +def run(request){ + return 'SAVE'; +}` + const result = GroovyScriptConvertorUtil.updateScriptMeta(script,'{trigger:"SAVE"}'); + console.log(result); + const title = GroovyScriptConvertorUtil.getScriptMeta(result) + expect(title).toEqual(`{trigger:"SAVE"}`); + }); + }); }); \ No newline at end of file diff --git a/frontend/packages/flow-core/tests/test.d.ts b/frontend/packages/flow-core/tests/test.d.ts new file mode 100644 index 00000000..e48dee96 --- /dev/null +++ b/frontend/packages/flow-core/tests/test.d.ts @@ -0,0 +1 @@ +/// diff --git a/frontend/packages/flow-core/tests/tsconfig.json b/frontend/packages/flow-core/tests/tsconfig.json new file mode 100644 index 00000000..5eac80a2 --- /dev/null +++ b/frontend/packages/flow-core/tests/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../tsconfig.json", + "include": [".", "../rstest.setup.ts"], + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["../src/*"] + } + } +} diff --git a/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/components/branch-adder/index.tsx b/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/components/branch-adder/index.tsx index 731244ee..b0038edd 100644 --- a/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/components/branch-adder/index.tsx +++ b/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/components/branch-adder/index.tsx @@ -36,9 +36,6 @@ export const BranchAdderRender: React.FC = (props) => { operation.addBlock( node, block, - { - index: 0, - } ); setTimeout(() => { handleClose(); diff --git a/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/hooks/use-editor-props.ts b/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/hooks/use-editor-props.ts index dbd3550a..39105a83 100644 --- a/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/hooks/use-editor-props.ts +++ b/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/hooks/use-editor-props.ts @@ -13,11 +13,16 @@ import {FlowDocumentJSON, FlowNodeRegistry} from "@/components/design-editor/typ import {Adder} from "@/components/design-editor/components/node-adder"; import {BranchAdder} from "@/components/design-editor/components/branch-adder"; import {Collapse} from "../components/collapse"; +import {useDesignContext} from "@/components/design-panel/hooks/use-design-context"; export function useEditorProps(initialData: FlowDocumentJSON, nodeRegistries: FlowNodeRegistry[]): FixedLayoutProps { const {token} = theme.useToken(); + const {context} = useDesignContext(); + + const presenter = context.getPresenter(); + return useMemo( () => ({ /** @@ -150,6 +155,8 @@ export function useEditorProps(initialData: FlowDocumentJSON, nodeRegistries: Fl // Listen change to trigger auto save const data = ctx.document.toJSON(); console.log('flow-engine auto save: ', data); + presenter.syncNodes(data.nodes); + }, 100), }, /** diff --git a/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/node-components/action/modal.tsx b/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/node-components/action/modal.tsx index 3e8dfa3e..78940826 100644 --- a/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/node-components/action/modal.tsx +++ b/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/node-components/action/modal.tsx @@ -12,18 +12,27 @@ interface ActionModalProps { options: any[]; } -export const ActionModal: React.FC = (props) => { - const custom = props.custom; +interface CustomScriptViewProps{ + options: any[]; + form: FormInstance; +} + +const CustomScriptView:React.FC = (props)=>{ + + const trigger = props.form.getFieldValue("trigger") as string; + + const [currentTrigger,setCurrentTrigger] = React.useState(trigger); const handleChangeNodeType = (value: string) => { const script = props.form.getFieldValue('script') as string; - const returnData = GroovyScriptConvertorUtil.getReturnScript(script).trim(); let groovy; - if (returnData) { + if (script) { + const returnData = GroovyScriptConvertorUtil.getReturnScript(script).trim(); groovy = script.replace(returnData, `'${value}'`); + groovy = GroovyScriptConvertorUtil.updateScriptMeta(groovy,`{"trigger":"${value}"}`); } else { - groovy = `// 自定义脚本,返回的数据为动作类型 + groovy = `// @CUSTOM_SCRIPT 自定义脚本,返回的数据为动作类型 // @SCRIPT_META {"trigger":"${value}"} def run(request){ return '${value}'; @@ -31,8 +40,57 @@ export const ActionModal: React.FC = (props) => { ` } props.form.setFieldValue("script", GroovyScriptConvertorUtil.formatScript(groovy)); + setCurrentTrigger(value); } + return ( + + + 自定义脚本 + + 触发动作: + - - - - - )} - required={true} - help={"请先设置触发动作类型"} - - rules={[ - { - required: true, - message: '自定义脚本不能为空' - } - ]} - > - - - - + )} - diff --git a/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/node-components/condition/index.tsx b/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/node-components/condition/index.tsx index 093d812d..59757d94 100644 --- a/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/node-components/condition/index.tsx +++ b/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/node-components/condition/index.tsx @@ -4,6 +4,7 @@ import React from "react"; import {GroovyScriptPreview} from "@/components/script/components/groovy-script-preview"; import {EditOutlined} from "@ant-design/icons"; import {ConditionConfigModal} from "@/components/script/modal/condition-config-modal"; +import {useScriptVariables} from "@/components/design-editor/hooks/use-script-variables"; /** * 条件配置 @@ -13,6 +14,7 @@ export const ConditionScript = ()=>{ const [form] = Form.useForm(); const [visible,setVisible] = React.useState(false); + const scriptVariables = useScriptVariables(); return (
{ onCancel={()=>{setVisible(false);}} onConfirm={(value)=>{onChange(value)}} script={value} + variables={scriptVariables} /> )} diff --git a/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/node-components/header/index.tsx b/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/node-components/header/index.tsx index 916a1026..d078031f 100644 --- a/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/node-components/header/index.tsx +++ b/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/node-components/header/index.tsx @@ -112,6 +112,20 @@ export const NodeHeader: React.FC = (props) => { /> )} + {!isSidebar && ( + + {({field: {value, onChange}}: FieldRenderProps) => { + if (nodeType === 'INCLUSIVE_BRANCH' || nodeType === 'CONDITION_BRANCH' || nodeType === 'PARALLEL_BRANCH') { + return ( + <>优先级:{value} + ) + } + return ( + <> + ); + }} + + )} {isSidebar && ( diff --git a/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/node-components/node-hint/index.tsx b/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/node-components/node-hint/index.tsx index dd61cf59..403ff64a 100644 --- a/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/node-components/node-hint/index.tsx +++ b/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/node-components/node-hint/index.tsx @@ -1,22 +1,24 @@ import React from "react"; import {GroovyScriptConvertorUtil} from "@flow-engine/flow-core"; import {Field, FieldRenderProps} from "@flowgram.ai/fixed-layout-editor"; +import {Text} from "@flow-engine/flow-pc-ui"; -interface NodeHintProps{ - fieldName:string; +interface NodeHintProps { + fieldName: string; } -export const NodeHint:React.FC = (props) => { +export const NodeHint: React.FC = (props) => { return ( - - ) => ( - <> - {GroovyScriptConvertorUtil.getScriptTitle(value)} - - )} - /> - + ) => ( + + {GroovyScriptConvertorUtil.getScriptTitle(value)} + + )} + /> ) } \ No newline at end of file diff --git a/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/node-components/node-order/index.tsx b/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/node-components/node-order/index.tsx new file mode 100644 index 00000000..815ac2b7 --- /dev/null +++ b/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/node-components/node-order/index.tsx @@ -0,0 +1,38 @@ +import React from "react"; +import {Field, FieldRenderProps} from "@flowgram.ai/fixed-layout-editor"; +import {Form, Input} from "antd"; + + +export const NodeOrder = () => { + const [form] = Form.useForm(); + + return ( + + + ) => ( + { + onChange(event.target.value); + }} + /> + )} + /> + + + ) +} \ No newline at end of file diff --git a/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/nodes/condition-branch/form-meta.tsx b/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/nodes/condition-branch/form-meta.tsx index 60debdf1..352b0a3a 100644 --- a/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/nodes/condition-branch/form-meta.tsx +++ b/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/nodes/condition-branch/form-meta.tsx @@ -8,6 +8,7 @@ import {NodePanel} from "@/components/design-editor/node-components/panel"; import {ConditionScript} from "@/components/design-editor/node-components/condition"; import React from "react"; import {NodeHint} from "@/components/design-editor/node-components/node-hint"; +import {NodeOrder} from "@/components/design-editor/node-components/node-order"; export const renderForm = (data: FormRenderProps) => { const isSidebar = useIsSidebar(); @@ -15,6 +16,7 @@ export const renderForm = (data: FormRenderProps) => { return ( + ); diff --git a/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/nodes/condition/form-meta.tsx b/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/nodes/condition/form-meta.tsx index 99554465..369da9ea 100644 --- a/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/nodes/condition/form-meta.tsx +++ b/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/nodes/condition/form-meta.tsx @@ -3,14 +3,17 @@ import {FormMeta, FormRenderProps, ValidateTrigger,} from '@flowgram.ai/fixed-la import {FlowNodeJSON} from '../../typings'; import {BranchAdderRender} from "@/components/design-editor/components/branch-adder"; +import {NodePanel} from "@/components/design-editor/node-components/panel"; -export const renderForm = ({form}: FormRenderProps) => { +export const renderForm = (data: FormRenderProps) => { return ( - + + + ); }; diff --git a/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/nodes/inclusive-branch/form-meta.tsx b/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/nodes/inclusive-branch/form-meta.tsx index 60debdf1..352b0a3a 100644 --- a/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/nodes/inclusive-branch/form-meta.tsx +++ b/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/nodes/inclusive-branch/form-meta.tsx @@ -8,6 +8,7 @@ import {NodePanel} from "@/components/design-editor/node-components/panel"; import {ConditionScript} from "@/components/design-editor/node-components/condition"; import React from "react"; import {NodeHint} from "@/components/design-editor/node-components/node-hint"; +import {NodeOrder} from "@/components/design-editor/node-components/node-order"; export const renderForm = (data: FormRenderProps) => { const isSidebar = useIsSidebar(); @@ -15,6 +16,7 @@ export const renderForm = (data: FormRenderProps) => { return ( + ); diff --git a/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/nodes/inclusive/form-meta.tsx b/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/nodes/inclusive/form-meta.tsx index 958fd32f..a81c3345 100644 --- a/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/nodes/inclusive/form-meta.tsx +++ b/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/nodes/inclusive/form-meta.tsx @@ -3,27 +3,30 @@ import {FormMeta, FormRenderProps, ValidateTrigger,} from '@flowgram.ai/fixed-la import {FlowNodeJSON} from '../../typings'; import {BranchAdderRender} from "@/components/design-editor/components/branch-adder"; +import {NodePanel} from "@/components/design-editor/node-components/panel"; -export const renderForm = ({form}: FormRenderProps) => { +export const renderForm = (data: FormRenderProps) => { return ( - + + + ); }; export const formMeta: FormMeta = { - render: renderForm, - validateTrigger: ValidateTrigger.onChange, - validate: { - title: ({ value }: { value: string }) => (value ? undefined : 'Title is required'), - }, - effect: { - title: syncVariableTitle, - outputs: provideJsonSchemaOutputs, - }, + render: renderForm, + validateTrigger: ValidateTrigger.onChange, + validate: { + title: ({value}: { value: string }) => (value ? undefined : 'Title is required'), + }, + effect: { + title: syncVariableTitle, + outputs: provideJsonSchemaOutputs, + }, }; diff --git a/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/nodes/parallel/form-meta.tsx b/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/nodes/parallel/form-meta.tsx index a932ed6f..852e1db0 100644 --- a/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/nodes/parallel/form-meta.tsx +++ b/frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/nodes/parallel/form-meta.tsx @@ -3,26 +3,29 @@ import {FormMeta, FormRenderProps, ValidateTrigger,} from '@flowgram.ai/fixed-la import {FlowNodeJSON} from '../../typings'; import {BranchAdderRender} from "@/components/design-editor/components/branch-adder"; +import {NodePanel} from "@/components/design-editor/node-components/panel"; -export const renderForm = ({form}: FormRenderProps) => { +export const renderForm = (data: FormRenderProps) => { return ( - + + + ); }; export const formMeta: FormMeta = { - render: renderForm, - validateTrigger: ValidateTrigger.onChange, - validate: { - title: ({ value }: { value: string }) => (value ? undefined : 'Title is required'), - }, - effect: { - title: syncVariableTitle, - outputs: provideJsonSchemaOutputs, - }, + render: renderForm, + validateTrigger: ValidateTrigger.onChange, + validate: { + title: ({value}: { value: string }) => (value ? undefined : 'Title is required'), + }, + effect: { + title: syncVariableTitle, + outputs: provideJsonSchemaOutputs, + }, }; diff --git a/frontend/packages/flow-pc/flow-pc-design/src/components/design-panel/layout/header.tsx b/frontend/packages/flow-pc/flow-pc-design/src/components/design-panel/layout/header.tsx index b290f072..7362be6f 100644 --- a/frontend/packages/flow-pc/flow-pc-design/src/components/design-panel/layout/header.tsx +++ b/frontend/packages/flow-pc/flow-pc-design/src/components/design-panel/layout/header.tsx @@ -1,7 +1,8 @@ import React from "react"; -import {Button, Space, Tabs, message} from "antd"; +import {Button, message, Space, Tabs} from "antd"; import {LayoutHeaderHeight, TabPanelType} from "../types"; import {useDesignContext} from "../hooks/use-design-context"; +import {CloseOutlined, SaveOutlined } from "@ant-design/icons"; const Left = () => { return ( @@ -17,8 +18,10 @@ const Right = () => { return ( - + ) } diff --git a/frontend/packages/flow-pc/flow-pc-design/src/components/design-panel/manager/node.ts b/frontend/packages/flow-pc/flow-pc-design/src/components/design-panel/manager/node.ts index 1cf8649b..31fb4138 100644 --- a/frontend/packages/flow-pc/flow-pc-design/src/components/design-panel/manager/node.ts +++ b/frontend/packages/flow-pc/flow-pc-design/src/components/design-panel/manager/node.ts @@ -97,6 +97,43 @@ interface MappingData { [key: string]: any; } + +export class NodeManger{ + private readonly nodes: FlowNode[]; + private readonly nodeList: FlowNode[]; + + + constructor(nodes: FlowNode[]) { + this.nodes = nodes; + this.nodeList = []; + this.fetchNodes(this.nodes); + } + + private fetchNodes(nodes: FlowNode[]) { + for (const node of nodes) { + this.nodeList.push(node); + const blocks = node.blocks || []; + if (node.blocks && node.blocks.length > 0) { + this.fetchNodes(blocks); + } + } + } + + + /** + * 获取节点 + * @param id 节点id + */ + public getNode(id:string){ + for (const node of this.nodeList) { + if (node.id === id) { + return node; + } + } + return null; + } +} + /** * 节点关系分析管理,分析所有的节点,可回退的节点等信息 */ diff --git a/frontend/packages/flow-pc/flow-pc-design/src/components/design-panel/presenters/index.ts b/frontend/packages/flow-pc/flow-pc-design/src/components/design-panel/presenters/index.ts index ff495b75..792a3d3e 100644 --- a/frontend/packages/flow-pc/flow-pc-design/src/components/design-panel/presenters/index.ts +++ b/frontend/packages/flow-pc/flow-pc-design/src/components/design-panel/presenters/index.ts @@ -2,7 +2,7 @@ import {DesignPanelApi, FlowNode, initStateData, State, TabPanelType} from "../t import {Dispatch} from "@flow-engine/flow-core"; import {FormActionContext} from "@flow-engine/flow-types"; import {WorkflowFormManager} from "@/components/design-panel/manager/form"; -import {NodeConvertorManager} from "@/components/design-panel/manager/node"; +import {NodeConvertorManager, NodeManger} from "@/components/design-panel/manager/node"; import {WorkflowConvertor} from "@/components/design-panel/presenters/convertor"; export class Presenter { @@ -24,16 +24,32 @@ export class Presenter { return this.formActionContext; } + /** + * 手动同步节点数据 + * @param nodes + */ + public syncNodes(nodes: any[]) { + const nodeConvertorManager = new NodeConvertorManager(); + const data = nodeConvertorManager.toData(nodes); + this.state = { + ...this.state, + workflow: { + ...this.state.workflow, + nodes: data, + } + } + } + public syncState(state: State) { this.state = state; } private mergeWorkflow(prevWorkflow: any, currentWorkflow: any) { - const nodes:FlowNode[] = []; - if(currentWorkflow.nodes && currentWorkflow.nodes.length > 0){ + const nodes: FlowNode[] = []; + if (currentWorkflow.nodes && currentWorkflow.nodes.length > 0) { nodes.push(...currentWorkflow.nodes); - }else { - if(prevWorkflow.nodes && prevWorkflow.nodes.length > 0){ + } else { + if (prevWorkflow.nodes && prevWorkflow.nodes.length > 0) { nodes.push(...prevWorkflow.nodes); } } @@ -44,7 +60,7 @@ export class Presenter { ...prevWorkflow.form, ...currentWorkflow.form, }, - nodes:nodes + nodes: nodes } } @@ -129,7 +145,23 @@ export class Presenter { public async createNode(form: string, type: string) { const flowNode = await this.api.createNode(type); const nodeManager = new NodeConvertorManager(); - return nodeManager.toItemRender(flowNode); + const nodeManger = new NodeManger(this.state.workflow.nodes || []); + const currentNode = nodeManger.getNode(form); + const block = nodeManager.toItemRender(flowNode); + if (currentNode) { + if (currentNode.blocks) { + const order = currentNode.blocks.length + 1; + return { + ...block, + data: { + ...block.data, + order: order + } + } + } + } + + return block; } diff --git a/frontend/packages/flow-pc/flow-pc-design/src/components/design-panel/tabs/form.tsx b/frontend/packages/flow-pc/flow-pc-design/src/components/design-panel/tabs/form.tsx index 9cb9f65f..3f3f7165 100644 --- a/frontend/packages/flow-pc/flow-pc-design/src/components/design-panel/tabs/form.tsx +++ b/frontend/packages/flow-pc/flow-pc-design/src/components/design-panel/tabs/form.tsx @@ -1,15 +1,30 @@ import React, {useState} from "react"; -import {Panel} from "@flow-engine/flow-pc-ui"; -import {Table, TableProps} from"@flow-engine/flow-pc-ui"; -import {Button, Flex, Form, FormInstance, Input, Modal, Popconfirm, Select, Space, Switch, Tabs,Empty, Row, Col} from "antd"; +import {Panel, Table, TableProps} from "@flow-engine/flow-pc-ui"; +import { + Button, + Col, + Empty, + Flex, + Form, + FormInstance, + Input, + Modal, + Popconfirm, + Row, + Select, + Space, + Switch, + Tabs +} from "antd"; import {dataTypeOptions} from "@flow-engine/flow-types"; import {useDesignContext} from "@/components/design-panel/hooks/use-design-context"; import {WorkflowFormManager} from "@/components/design-panel/manager/form"; +import {DeleteOutlined, FolderAddOutlined, PlusOutlined } from "@ant-design/icons"; interface FormTableProps { name: string; code: string; - delete: boolean; + mainForm: boolean; } interface FormFieldModalProps { @@ -54,7 +69,7 @@ const FormFieldModal: React.FC = (props) => { > - + = (props) => { const [fieldForm] = Form.useForm(); const [editable, setEditable] = useState(false); + const [subForm] = Form.useForm(); + const [subFormVisible, setSubFormVisible] = useState(false); + const columns: TableProps['columns'] = [ { dataIndex: 'id', @@ -243,8 +261,8 @@ const FormTable: React.FC = (props) => { title: '字段类型', render: (value, record) => { let label = ''; - for(const option of dataTypeOptions) { - if(option.value == value){ + for (const option of dataTypeOptions) { + if (option.value == value) { label = option.label; } } @@ -316,26 +334,54 @@ const FormTable: React.FC = (props) => { {name} - {props.delete && ( + {props.mainForm && ( + + )} + {!props.mainForm && ( { presenter.removeWorkflowSubForm(props.code); }} > - + )} - + ) }} /> + + { + presenter.addWorkflowSubForm(values); + }} + onClose={() => { + setSubFormVisible(false) + }} + /> + = (props) => { } export const TabForm = () => { - - const [subFormVisible, setSubFormVisible] = useState(false); - const [subForm] = Form.useForm(); - const {state, context} = useDesignContext(); - - const presenter = context.getPresenter(); - + const {state} = useDesignContext(); const mainCode = state.workflow.form.code; const mainName = state.workflow.form.name; - const subForms = state.workflow.form.subForms || []; const items = subForms.map(item => { @@ -369,11 +408,11 @@ export const TabForm = () => { return { key: item.code, label: title, - children: + children: } }); - if(!mainCode){ + if (!mainCode) { return ( ) @@ -381,34 +420,12 @@ export const TabForm = () => { return ( - + { - subForm.resetFields(); - setSubFormVisible(true) - }}> - 添加子表 - - ) - }} - /> - - { - presenter.addWorkflowSubForm(values); - }} - onClose={() => { - setSubFormVisible(false) - }} /> ) diff --git a/frontend/packages/flow-pc/flow-pc-design/src/components/script/components/condition/components/condition-group/condition.tsx b/frontend/packages/flow-pc/flow-pc-design/src/components/script/components/condition/components/condition-group/condition.tsx index 3c947f21..66d2fbc6 100644 --- a/frontend/packages/flow-pc/flow-pc-design/src/components/script/components/condition/components/condition-group/condition.tsx +++ b/frontend/packages/flow-pc/flow-pc-design/src/components/script/components/condition/components/condition-group/condition.tsx @@ -1,23 +1,126 @@ import {Condition} from "@/components/script/components/condition/typings"; import {Input, Select, Space} from "antd"; import React from "react"; +import {useConditionContext} from "@/components/script/components/condition/hooks/use-condition-context"; +import {GroovyVariableMapping} from "@/components/script/typings"; interface ConditionItemViewProps { data?: Condition; + id: string; + location: 'left' | 'right'; +} + +interface ConditionInputProps { + value: string; + onChange: (value: Condition) => void; +} + +const VariableSelect: React.FC = (props) => { + + const {state} = useConditionContext(); + + const variables = React.useMemo(() => { + const groups = new Map(); + + for (const mapping of state.variables) { + const existing = groups.get(mapping.tag) || []; + existing.push(mapping); + groups.set(mapping.tag, existing); + } + + const options: any[] = []; + for (const group of Array.from(groups.keys())) { + const children = groups.get(group) || []; + + options.push({ + label: group, + options: children, + }) + } + + return options; + }, [state.variables]); + + const handleChange = (value: string, option: any) => { + props.onChange({ + label: option.label, + value: option.value, + dataType: option.type, + type: 'variable', + }); + } + + return ( + { + handleChange(event.target.value); + }} + /> + ) } export const ConditionItemView: React.FC = (props) => { - const label = props.data?.label || '未设置'; - const [type,setType] = React.useState('variable'); + const [type, setType] = React.useState(props.data?.type || 'variable'); + + const {context} = useConditionContext(); + + const presenter = context.getPresenter().getConditionGroupPresenter(); + + const handleUpdate = (value: any) => { + const latest = { + ...props.data, + ...value + } + presenter.updateCondition(props.id,props.location, latest); + } + + React.useEffect(()=>{ + if(props.data) { + setType(props.data.type); + } + },[props.data]) return ( { + handleUpdate(value) + }} /> )} {type === "input" && ( - { + handleUpdate(value) + }} /> )} diff --git a/frontend/packages/flow-pc/flow-pc-design/src/components/script/components/condition/components/condition-group/group.tsx b/frontend/packages/flow-pc/flow-pc-design/src/components/script/components/condition/components/condition-group/group.tsx index c7f01564..43f62804 100644 --- a/frontend/packages/flow-pc/flow-pc-design/src/components/script/components/condition/components/condition-group/group.tsx +++ b/frontend/packages/flow-pc/flow-pc-design/src/components/script/components/condition/components/condition-group/group.tsx @@ -43,7 +43,11 @@ export const Group = () => { title: '左侧参数', dataIndex: 'left', render: (_, record) => { - return () + return () } }, { @@ -51,7 +55,10 @@ export const Group = () => { title: '条件关系', dataIndex: 'type', render: (_, record) => { - return () + return () } }, { @@ -59,7 +66,11 @@ export const Group = () => { title: '右侧参数', dataIndex: 'right', render: (_, record) => { - return () + return () } }, { diff --git a/frontend/packages/flow-pc/flow-pc-design/src/components/script/components/condition/components/condition-group/type.tsx b/frontend/packages/flow-pc/flow-pc-design/src/components/script/components/condition/components/condition-group/type.tsx index 01e8255f..42ea8ef9 100644 --- a/frontend/packages/flow-pc/flow-pc-design/src/components/script/components/condition/components/condition-group/type.tsx +++ b/frontend/packages/flow-pc/flow-pc-design/src/components/script/components/condition/components/condition-group/type.tsx @@ -1,19 +1,30 @@ import {RelationType, relationTypeOptions} from "@/components/script/components/condition/typings"; +import {Select} from "antd"; import React from "react"; +import {useConditionContext} from "@/components/script/components/condition/hooks/use-condition-context"; interface ConditionTypeViewProps { type?: RelationType; + id: string; } export const ConditionTypeView: React.FC = (props) => { const type = props.type; - const typeLabel = relationTypeOptions.find(item => item.value === type); - if (typeLabel) { - return ( - {typeLabel.label} - ) + + const {context} = useConditionContext(); + const presenter = context.getPresenter().getConditionGroupPresenter(); + + const handleChangeType = (value: string) => { + presenter.updateType(props.id, value as RelationType); } + return ( - 未知 +