Compare commits

..

No commits in common. "b546cf3ad0e6bbb7a2f1d80a52fe3156506f7053" and "1e67e9333ec9a7d997e8dbe1f28af42121fc13fd" have entirely different histories.

5 changed files with 32 additions and 226 deletions

View File

@ -5,7 +5,7 @@ import { Button, Card, Popover } from "antd";
import SharedNode, { type SharedNodeProps } from "./_SharedNode"; import SharedNode, { type SharedNodeProps } from "./_SharedNode";
import AddNode from "./AddNode"; import AddNode from "./AddNode";
import ConditionNodeConfigForm, { ConditionItem, ConditionNodeConfigFormFieldValues, ConditionNodeConfigFormInstance } from "./ConditionNodeConfigForm"; import ConditionNodeConfigForm, { ConditionItem, ConditionNodeConfigFormFieldValues, ConditionNodeConfigFormInstance } from "./ConditionNodeConfigForm";
import { Expr, WorkflowNodeIoValueType } from "@/domain/workflow"; import { Expr, WorkflowNodeConfigForCondition } from "@/domain/workflow";
import { produce } from "immer"; import { produce } from "immer";
import { useWorkflowStore } from "@/stores/workflow"; import { useWorkflowStore } from "@/stores/workflow";
import { useZustandShallowSelector } from "@/hooks"; import { useZustandShallowSelector } from "@/hooks";
@ -29,15 +29,7 @@ const ConditionNode = ({ node, disabled, branchId, branchIndex }: ConditionNodeP
const formToExpression = (values: ConditionNodeConfigFormFieldValues): Expr => { const formToExpression = (values: ConditionNodeConfigFormFieldValues): Expr => {
// 创建单个条件的表达式 // 创建单个条件的表达式
const createComparisonExpr = (condition: ConditionItem): Expr => { const createComparisonExpr = (condition: ConditionItem): Expr => {
const selectors = condition.leftSelector.split("#"); const left: Expr = { type: "var", selector: condition.leftSelector };
const left: Expr = {
type: "var",
selector: {
id: selectors[0],
name: selectors[1],
type: selectors[2] as WorkflowNodeIoValueType,
},
};
const right: Expr = { type: "const", value: condition.rightValue || "" }; const right: Expr = { type: "const", value: condition.rightValue || "" };
return { return {

View File

@ -1,7 +1,6 @@
import { forwardRef, memo, useEffect, useImperativeHandle, useState } from "react"; import { forwardRef, memo, useEffect, useImperativeHandle, useState } from "react";
import { Button, Card, Form, Input, Select, Radio } from "antd"; import { Button, Card, Form, Input, Select, Space, Radio } from "antd";
import { PlusOutlined, DeleteOutlined } from "@ant-design/icons"; import { PlusOutlined, DeleteOutlined } from "@ant-design/icons";
import i18n from "@/i18n";
import { import {
WorkflowNodeConfigForCondition, WorkflowNodeConfigForCondition,
@ -13,16 +12,14 @@ import {
isVarExpr, isVarExpr,
WorkflowNode, WorkflowNode,
workflowNodeIOOptions, workflowNodeIOOptions,
WorkflowNodeIoValueType,
} from "@/domain/workflow"; } from "@/domain/workflow";
import { FormInstance } from "antd"; import { FormInstance } from "antd";
import { useZustandShallowSelector } from "@/hooks"; import { useZustandShallowSelector } from "@/hooks";
import { useWorkflowStore } from "@/stores/workflow"; import { useWorkflowStore } from "@/stores/workflow";
import { useTranslation } from "react-i18next";
// 表单内部使用的扁平结构 - 修改后只保留必要字段 // 表单内部使用的扁平结构 - 修改后只保留必要字段
export interface ConditionItem { export interface ConditionItem {
leftSelector: string; leftSelector: WorkflowNodeIOValueSelector;
operator: ComparisonOperator; operator: ComparisonOperator;
rightValue: string; rightValue: string;
} }
@ -53,7 +50,7 @@ const initFormModel = (): ConditionNodeConfigFormFieldValues => {
return { return {
conditions: [ conditions: [
{ {
leftSelector: "", leftSelector: undefined as unknown as WorkflowNodeIOValueSelector,
operator: "==", operator: "==",
rightValue: "", rightValue: "",
}, },
@ -74,7 +71,7 @@ const expressionToForm = (expr?: Expr): ConditionNodeConfigFormFieldValues => {
// 确保左侧是变量,右侧是常量 // 确保左侧是变量,右侧是常量
if (isVarExpr(expr.left) && isConstExpr(expr.right)) { if (isVarExpr(expr.left) && isConstExpr(expr.right)) {
conditions.push({ conditions.push({
leftSelector: `${expr.left.selector.id}#${expr.left.selector.name}#${expr.left.selector.type}`, leftSelector: expr.left.selector,
operator: expr.op, operator: expr.op,
rightValue: String(expr.right.value), rightValue: String(expr.right.value),
}); });
@ -94,43 +91,8 @@ const expressionToForm = (expr?: Expr): ConditionNodeConfigFormFieldValues => {
}; };
}; };
// 根据变量类型获取适当的操作符选项
const getOperatorsByType = (type: string): { value: ComparisonOperator; label: string }[] => {
switch (type) {
case "number":
case "string":
return [
{ value: "==", label: i18n.t("workflow_node.condition.form.comparison.equal") },
{ value: "!=", label: i18n.t("workflow_node.condition.form.comparison.not_equal") },
{ value: ">", label: i18n.t("workflow_node.condition.form.comparison.greater_than") },
{ value: ">=", label: i18n.t("workflow_node.condition.form.comparison.greater_than_or_equal") },
{ value: "<", label: i18n.t("workflow_node.condition.form.comparison.less_than") },
{ value: "<=", label: i18n.t("workflow_node.condition.form.comparison.less_than_or_equal") },
];
case "boolean":
return [{ value: "is", label: i18n.t("workflow_node.condition.form.comparison.is") }];
default:
return [];
}
};
// 从选择器字符串中提取变量类型
const getVariableTypeFromSelector = (selector: string): string => {
if (!selector) return "string";
// 假设选择器格式为 "id#name#type"
const parts = selector.split("#");
if (parts.length >= 3) {
return parts[2].toLowerCase() || "string";
}
return "string";
};
const ConditionNodeConfigForm = forwardRef<ConditionNodeConfigFormInstance, ConditionNodeConfigFormProps>( const ConditionNodeConfigForm = forwardRef<ConditionNodeConfigFormInstance, ConditionNodeConfigFormProps>(
({ className, style, disabled, initialValues, onValuesChange, nodeId }, ref) => { ({ className, style, disabled, initialValues, onValuesChange, nodeId }, ref) => {
const { t } = useTranslation();
const prefix = "workflow_node.condition.form";
const { getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"])); const { getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
const [form] = Form.useForm<ConditionNodeConfigFormFieldValues>(); const [form] = Form.useForm<ConditionNodeConfigFormFieldValues>();
@ -165,12 +127,6 @@ const ConditionNodeConfigForm = forwardRef<ConditionNodeConfigFormInstance, Cond
// 表单值变更处理 // 表单值变更处理
const handleFormChange = (_: undefined, values: ConditionNodeConfigFormFieldValues) => { const handleFormChange = (_: undefined, values: ConditionNodeConfigFormFieldValues) => {
setFormModel(values); setFormModel(values);
if (onValuesChange) {
// 将表单值转换为表达式
const expression = formToExpression(values);
onValuesChange({ expression });
}
}; };
return ( return (
@ -185,78 +141,33 @@ const ConditionNodeConfigForm = forwardRef<ConditionNodeConfigFormInstance, Cond
className="mb-3" className="mb-3"
extra={fields.length > 1 ? <Button icon={<DeleteOutlined />} danger type="text" onClick={() => remove(name)} /> : null} extra={fields.length > 1 ? <Button icon={<DeleteOutlined />} danger type="text" onClick={() => remove(name)} /> : null}
> >
{/* 将三个表单项放在一行 */}
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
{/* 左侧变量选择器 */} {/* 左侧变量选择器 */}
<Form.Item <Form.Item {...restField} name={[name, "leftSelector"]} className="mb-0 flex-1" rules={[{ required: true, message: "请选择变量" }]}>
{...restField}
name={[name, "leftSelector"]}
className="mb-0 flex-1"
rules={[{ required: true, message: t(`${prefix}.variable.errmsg`) }]}
>
<Select <Select
placeholder={t(`${prefix}.variable.placeholder`)} placeholder="选择变量"
options={previousNodes.map((item) => { options={previousNodes.map((item) => {
return workflowNodeIOOptions(item); return workflowNodeIOOptions(item);
})} })}
/> ></Select>
</Form.Item> </Form.Item>
{/* 操作符 - 动态根据变量类型改变选项 */} {/* 操作符 */}
<Form.Item <Form.Item {...restField} name={[name, "operator"]} className="mb-0 w-32" rules={[{ required: true, message: "请选择" }]}>
noStyle <Select>
shouldUpdate={(prevValues, currentValues) => { <Select.Option value="=="> (==)</Select.Option>
return prevValues.conditions?.[name]?.leftSelector !== currentValues.conditions?.[name]?.leftSelector; <Select.Option value="!="> (!=)</Select.Option>
}} <Select.Option value=">"> (&gt;)</Select.Option>
> <Select.Option value=">="> (&gt;=)</Select.Option>
{({ getFieldValue }) => { <Select.Option value="<"> (&lt;)</Select.Option>
const leftSelector = getFieldValue(["conditions", name, "leftSelector"]); <Select.Option value="<="> (&lt;=)</Select.Option>
const varType = getVariableTypeFromSelector(leftSelector); </Select>
const operators = getOperatorsByType(varType);
return (
<Form.Item
{...restField}
name={[name, "operator"]}
className="mb-0 w-32"
rules={[{ required: true, message: t(`${prefix}.operator.errmsg`) }]}
>
<Select options={operators} />
</Form.Item>
);
}}
</Form.Item> </Form.Item>
{/* 右侧输入控件 - 根据变量类型使用不同的控件 */} {/* 右侧常量输入框 */}
<Form.Item <Form.Item {...restField} name={[name, "rightValue"]} className="mb-0 flex-1" rules={[{ required: true, message: "请输入值" }]}>
noStyle <Input placeholder="输入值" />
shouldUpdate={(prevValues, currentValues) => {
return prevValues.conditions?.[name]?.leftSelector !== currentValues.conditions?.[name]?.leftSelector;
}}
>
{({ getFieldValue }) => {
const leftSelector = getFieldValue(["conditions", name, "leftSelector"]);
const varType = getVariableTypeFromSelector(leftSelector);
return (
<Form.Item
{...restField}
name={[name, "rightValue"]}
className="mb-0 flex-1"
rules={[{ required: true, message: t(`${prefix}.value.errmsg`) }]}
>
{varType === "boolean" ? (
<Select placeholder={t(`${prefix}.value.boolean.placeholder`)}>
<Select.Option value="true">{t(`${prefix}.value.boolean.true`)}</Select.Option>
<Select.Option value="false">{t(`${prefix}.value.boolean.false`)}</Select.Option>
</Select>
) : varType === "number" ? (
<Input type="number" placeholder={t(`${prefix}.value.number.placeholder`)} />
) : (
<Input placeholder={t(`${prefix}.value.string.placeholder`)} />
)}
</Form.Item>
);
}}
</Form.Item> </Form.Item>
</div> </div>
</Card> </Card>
@ -268,7 +179,7 @@ const ConditionNodeConfigForm = forwardRef<ConditionNodeConfigFormInstance, Cond
type="dashed" type="dashed"
onClick={() => onClick={() =>
add({ add({
leftSelector: "", leftSelector: undefined as unknown as WorkflowNodeIOValueSelector,
operator: "==", operator: "==",
rightValue: "", rightValue: "",
}) })
@ -276,7 +187,7 @@ const ConditionNodeConfigForm = forwardRef<ConditionNodeConfigFormInstance, Cond
block block
icon={<PlusOutlined />} icon={<PlusOutlined />}
> >
{t(`${prefix}.add_condition.button`)}
</Button> </Button>
</Form.Item> </Form.Item>
</> </>
@ -284,10 +195,10 @@ const ConditionNodeConfigForm = forwardRef<ConditionNodeConfigFormInstance, Cond
</Form.List> </Form.List>
{formModel.conditions && formModel.conditions.length > 1 && ( {formModel.conditions && formModel.conditions.length > 1 && (
<Form.Item name="logicalOperator" label={t(`${prefix}.logical_operator.label`)}> <Form.Item name="logicalOperator" label="条件逻辑">
<Radio.Group buttonStyle="solid"> <Radio.Group buttonStyle="solid">
<Radio.Button value="and">{t(`${prefix}.logical_operator.and`)}</Radio.Button> <Radio.Button value="and"> (AND)</Radio.Button>
<Radio.Button value="or">{t(`${prefix}.logical_operator.or`)}</Radio.Button> <Radio.Button value="or"> (OR)</Radio.Button>
</Radio.Group> </Radio.Group>
</Form.Item> </Form.Item>
)} )}
@ -296,57 +207,5 @@ const ConditionNodeConfigForm = forwardRef<ConditionNodeConfigFormInstance, Cond
} }
); );
// 表单值转换为表达式结构 (需要添加)
const formToExpression = (values: ConditionNodeConfigFormFieldValues): Expr => {
const createComparisonExpr = (condition: ConditionItem): Expr => {
const [id, name, typeStr] = condition.leftSelector.split("#");
const type = typeStr as WorkflowNodeIoValueType;
const left: Expr = {
type: "var",
selector: { id, name, type },
};
let rightValue: any = condition.rightValue;
if (type === "number") {
rightValue = Number(condition.rightValue);
} else if (type === "boolean") {
rightValue = condition.rightValue === "true";
}
const right: Expr = {
type: "const",
value: rightValue,
};
return {
type: "compare",
op: condition.operator,
left,
right,
};
};
// 如果只有一个条件,直接返回比较表达式
if (values.conditions.length === 1) {
return createComparisonExpr(values.conditions[0]);
}
// 多个条件,通过逻辑运算符连接
let expr: Expr = createComparisonExpr(values.conditions[0]);
for (let i = 1; i < values.conditions.length; i++) {
expr = {
type: "logical",
op: values.logicalOperator,
left: expr,
right: createComparisonExpr(values.conditions[i]),
};
}
return expr;
};
export default memo(ConditionNodeConfigForm); export default memo(ConditionNodeConfigForm);

View File

@ -185,11 +185,8 @@ export type WorkflowNodeIO = {
export type WorkflowNodeIOValueSelector = { export type WorkflowNodeIOValueSelector = {
id: string; id: string;
name: string; name: string;
type: WorkflowNodeIoValueType;
}; };
export type WorkflowNodeIoValueType = "string" | "number" | "boolean";
type WorkflowNodeIOOptions = { type WorkflowNodeIOOptions = {
label: string; label: string;
value: string; value: string;
@ -207,18 +204,18 @@ export const workflowNodeIOOptions = (node: WorkflowNode) => {
case "certificate": case "certificate":
rs.options.push({ rs.options.push({
label: `${node.name} - ${output.label} - 是否有效`, label: `${node.name} - ${output.label} - 是否有效`,
value: `${node.id}#${output.name}.validated#boolean`, value: `${node.id}#${output.name}.validated`,
}); });
rs.options.push({ rs.options.push({
label: `${node.name} - ${output.label} - 剩余天数`, label: `${node.name} - ${output.label} - 剩余天数`,
value: `${node.id}#${output.name}.daysLeft#number`, value: `${node.id}#${output.name}.daysLeft`,
}); });
break; break;
default: default:
rs.options.push({ rs.options.push({
label: `${node.name} - ${output.label}`, label: `${node.name} - ${output.label}`,
value: `${node.id}#${output.name}#${output.type}`, value: `${node.id}#${output.name}`,
}); });
break; break;
} }
@ -234,7 +231,7 @@ export const workflowNodeIOOptions = (node: WorkflowNode) => {
type Value = string | number | boolean; type Value = string | number | boolean;
export type ComparisonOperator = ">" | "<" | ">=" | "<=" | "==" | "!=" | "is"; export type ComparisonOperator = ">" | "<" | ">=" | "<=" | "==" | "!=";
export type LogicalOperator = "and" | "or" | "not"; export type LogicalOperator = "and" | "or" | "not";

View File

@ -790,26 +790,6 @@
"workflow_node.branch.label": "Parallel branch", "workflow_node.branch.label": "Parallel branch",
"workflow_node.condition.label": "Branch", "workflow_node.condition.label": "Branch",
"workflow_node.condition.form.variable.placeholder": "Please select variable",
"workflow_node.condition.form.variable.errmsg": "Please select variable",
"workflow_node.condition.form.operator.errmsg": "Please select operator",
"workflow_node.condition.form.value.errmsg": "Please enter value",
"workflow_node.condition.form.value.string.placeholder": "Please enter value",
"workflow_node.condition.form.value.number.placeholder": "Please enter value",
"workflow_node.condition.form.value.boolean.placeholder": "Please select value",
"workflow_node.condition.form.value.boolean.true": "True",
"workflow_node.condition.form.value.boolean.false": "False",
"workflow_node.condition.form.add_condition.button": "Add condition",
"workflow_node.condition.form.logical_operator.label": "Logical operator",
"workflow_node.condition.form.logical_operator.and": "Meet all conditions (AND)",
"workflow_node.condition.form.logical_operator.or": "Meet any condition (OR)",
"workflow_node.condition.form.comparison.equal": "Equal",
"workflow_node.condition.form.comparison.not_equal": "Not equal",
"workflow_node.condition.form.comparison.greater_than": "Greater than",
"workflow_node.condition.form.comparison.greater_than_or_equal": "Greater than or equal",
"workflow_node.condition.form.comparison.less_than": "Less than",
"workflow_node.condition.form.comparison.less_than_or_equal": "Less than or equal",
"workflow_node.condition.form.comparison.is": "Is",
"workflow_node.execute_result_branch.label": "Execution result branch", "workflow_node.execute_result_branch.label": "Execution result branch",
@ -817,4 +797,3 @@
"workflow_node.execute_failure.label": "If the previous node failed ..." "workflow_node.execute_failure.label": "If the previous node failed ..."
} }

View File

@ -789,26 +789,6 @@
"workflow_node.branch.label": "并行分支", "workflow_node.branch.label": "并行分支",
"workflow_node.condition.label": "分支", "workflow_node.condition.label": "分支",
"workflow_node.condition.form.variable.placeholder": "选择变量",
"workflow_node.condition.form.variable.errmsg": "请选择变量",
"workflow_node.condition.form.operator.errmsg": "请选择操作符",
"workflow_node.condition.form.value.errmsg": "请输入值",
"workflow_node.condition.form.value.string.placeholder": "输入值",
"workflow_node.condition.form.value.number.placeholder": "输入数值",
"workflow_node.condition.form.value.boolean.placeholder": "选择值",
"workflow_node.condition.form.value.boolean.true": "是",
"workflow_node.condition.form.value.boolean.false": "否",
"workflow_node.condition.form.add_condition.button": "添加条件",
"workflow_node.condition.form.logical_operator.label": "条件逻辑",
"workflow_node.condition.form.logical_operator.and": "满足所有条件 (AND)",
"workflow_node.condition.form.logical_operator.or": "满足任一条件 (OR)",
"workflow_node.condition.form.comparison.equal": "等于",
"workflow_node.condition.form.comparison.not_equal": "不等于",
"workflow_node.condition.form.comparison.greater_than": "大于",
"workflow_node.condition.form.comparison.greater_than_or_equal": "大于等于",
"workflow_node.condition.form.comparison.less_than": "小于",
"workflow_node.condition.form.comparison.less_than_or_equal": "小于等于",
"workflow_node.condition.form.comparison.is": "为",
"workflow_node.execute_result_branch.label": "执行结果分支", "workflow_node.execute_result_branch.label": "执行结果分支",
@ -816,4 +796,3 @@
"workflow_node.execute_failure.label": "若前序节点执行失败…" "workflow_node.execute_failure.label": "若前序节点执行失败…"
} }