mirror of
https://github.com/nocobase/nocobase
synced 2024-11-15 09:17:23 +00:00
feat(plugin-workflow): add create node component (#292)
This commit is contained in:
parent
5039896b16
commit
e002777b63
@ -65,7 +65,7 @@ export function parseStringValue(value: string, Types) {
|
||||
|
||||
return {
|
||||
type,
|
||||
options: paths.length ? (Types || VariableTypes)[type].parse(paths) : {}
|
||||
options: paths.length ? (Types || VariableTypes)[type]?.parse(paths) : {}
|
||||
};
|
||||
}
|
||||
|
||||
@ -252,7 +252,7 @@ export function Operand({
|
||||
|
||||
const { type } = operand;
|
||||
|
||||
const { component, appendTypeValue } = Types[type];
|
||||
const { component, appendTypeValue } = Types[type] || {};
|
||||
const VariableComponent = typeof component === 'function' ? component(operand) : NullRender;
|
||||
|
||||
return (
|
||||
|
156
packages/client/src/workflow/nodes/create.tsx
Normal file
156
packages/client/src/workflow/nodes/create.tsx
Normal file
@ -0,0 +1,156 @@
|
||||
import React from 'react';
|
||||
import { observer, useForm } from '@formily/react';
|
||||
import { action } from '@formily/reactive';
|
||||
import { Select } from 'antd';
|
||||
import { t } from 'i18next';
|
||||
import { css } from '@emotion/css';
|
||||
|
||||
import { SchemaComponent, useCollectionManager } from '../..';
|
||||
import { useCollectionFilterOptions } from '../../collection-manager/action-hooks';
|
||||
import { useFlowContext } from '../WorkflowCanvas';
|
||||
import { Operand, parseStringValue, VariableTypes, VariableTypesContext, BaseTypeSet } from '../calculators';
|
||||
import { FormItem } from '@formily/antd';
|
||||
|
||||
export default {
|
||||
title: '新增',
|
||||
type: 'create',
|
||||
group: 'model',
|
||||
fieldset: {
|
||||
collection: {
|
||||
type: 'string',
|
||||
title: '数据表',
|
||||
name: 'collection',
|
||||
required: true,
|
||||
'x-reactions': ['{{useCollectionDataSource()}}'],
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Select',
|
||||
},
|
||||
// multiple: {
|
||||
// type: 'boolean',
|
||||
// title: '多条数据',
|
||||
// name: 'multiple',
|
||||
// 'x-decorator': 'FormItem',
|
||||
// 'x-component': 'Checkbox',
|
||||
// 'x-component-props': {
|
||||
// disabled: true
|
||||
// }
|
||||
// },
|
||||
params: {
|
||||
type: 'object',
|
||||
name: 'params',
|
||||
title: '数据',
|
||||
'x-decorator': 'FormItem',
|
||||
properties: {
|
||||
values: {
|
||||
type: 'object',
|
||||
title: '',
|
||||
name: 'values',
|
||||
'x-component': 'DynamicFieldset',
|
||||
'x-component-props': {
|
||||
useProps() {
|
||||
const { values } = useForm();
|
||||
return { fields: useCollectionFilterOptions(values.collection) };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
view: {
|
||||
|
||||
},
|
||||
scope: {
|
||||
useCollectionDataSource() {
|
||||
return (field: any) => {
|
||||
const { collections = [] } = useCollectionManager();
|
||||
action.bound((data: any) => {
|
||||
field.dataSource = data.map(item => ({
|
||||
label: t(item.title),
|
||||
value: item.name
|
||||
}));
|
||||
})(collections);
|
||||
}
|
||||
}
|
||||
},
|
||||
components: {
|
||||
// NOTE: observer for watching useProps
|
||||
DynamicFieldset: observer(({ value, onChange, useProps }: any) => {
|
||||
const { fields } = useProps();
|
||||
|
||||
const VTypes = { ...VariableTypes,
|
||||
constant: {
|
||||
title: '常量',
|
||||
value: 'constant',
|
||||
options: undefined
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<fieldset className={css`
|
||||
margin-top: .5em;
|
||||
|
||||
.ant-formily-item{
|
||||
.ant-formily-item-label{
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
.ant-select,
|
||||
.ant-cascader-picker,
|
||||
.ant-picker,
|
||||
.ant-input-number,
|
||||
.ant-input-affix-wrapper{
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
`}>
|
||||
{fields.map(field => {
|
||||
const operand = typeof value[field.name] === 'string'
|
||||
? parseStringValue(value[field.name], VTypes)
|
||||
: { type: 'constant', value: value[field.name] };
|
||||
|
||||
return (
|
||||
<FormItem label={field.title}>
|
||||
<VariableTypesContext.Provider value={VTypes}>
|
||||
<Operand
|
||||
value={operand}
|
||||
onChange={(next) => {
|
||||
if (next.type !== operand.type && next.type === 'constant') {
|
||||
onChange({ ...value, [field.name]: null });
|
||||
} else {
|
||||
const { stringify } = VTypes[next.type];
|
||||
onChange({ ...value, [field.name]: stringify(next) });
|
||||
}
|
||||
}}
|
||||
>
|
||||
{operand.type === 'constant'
|
||||
? <SchemaComponent schema={field.schema} />
|
||||
: null
|
||||
}
|
||||
</Operand>
|
||||
</VariableTypesContext.Provider>
|
||||
</FormItem>
|
||||
);
|
||||
})}
|
||||
</fieldset>
|
||||
);
|
||||
})
|
||||
},
|
||||
getter({ type, options, onChange }) {
|
||||
const { collections = [] } = useCollectionManager();
|
||||
const { nodes } = useFlowContext();
|
||||
const { config } = nodes.find(n => n.id == options.nodeId);
|
||||
const collection = collections.find(item => item.name === config.collection) ?? { fields: [] };
|
||||
|
||||
return (
|
||||
<Select value={options.path} placeholder="选择字段" onChange={path => {
|
||||
onChange({ type, options: { ...options, path } });
|
||||
}}>
|
||||
{collection.fields
|
||||
.filter(field => BaseTypeSet.has(field.uiSchema.type))
|
||||
.map(field => (
|
||||
<Select.Option key={field.name} value={field.name}>{t(field.uiSchema.title)}</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
);
|
||||
}
|
||||
};
|
@ -12,6 +12,7 @@ import { AddButton, useFlowContext } from '../WorkflowCanvas';
|
||||
import { nodeClass, nodeCardClass, nodeHeaderClass, nodeTitleClass, nodeBlockClass } from '../style';
|
||||
|
||||
import query from './query';
|
||||
import create from './create';
|
||||
import condition from './condition';
|
||||
import parallel from './parallel';
|
||||
import calculation from './calculation';
|
||||
@ -59,6 +60,7 @@ export interface Instruction {
|
||||
export const instructions = new Registry<Instruction>();
|
||||
|
||||
instructions.register('query', query);
|
||||
instructions.register('create', create);
|
||||
instructions.register('condition', condition);
|
||||
instructions.register('parallel', parallel);
|
||||
instructions.register('calculation', calculation);
|
||||
@ -159,54 +161,58 @@ export function NodeDefaultView(props) {
|
||||
type: 'void',
|
||||
properties: {
|
||||
view: instruction.view,
|
||||
config: {
|
||||
type: 'void',
|
||||
title: '配置节点',
|
||||
'x-component': 'Action.Link',
|
||||
'x-component-props': {
|
||||
type: 'primary',
|
||||
},
|
||||
properties: {
|
||||
drawer: {
|
||||
...(Object.keys(instruction.fieldset).length
|
||||
? {
|
||||
config: {
|
||||
type: 'void',
|
||||
title: '配置节点',
|
||||
'x-component': 'Action.Drawer',
|
||||
'x-decorator': 'Form',
|
||||
'x-decorator-props': {
|
||||
useValues(options) {
|
||||
const node = useNodeContext();
|
||||
return useRequest(() => {
|
||||
return Promise.resolve({ data: node.config });
|
||||
}, options);
|
||||
}
|
||||
'x-component': 'Action.Link',
|
||||
'x-component-props': {
|
||||
type: 'primary',
|
||||
},
|
||||
properties: {
|
||||
...instruction.fieldset,
|
||||
actions: {
|
||||
drawer: {
|
||||
type: 'void',
|
||||
'x-component': 'Action.Drawer.Footer',
|
||||
properties: {
|
||||
cancel: {
|
||||
title: '{{t("Cancel")}}',
|
||||
'x-component': 'Action',
|
||||
'x-component-props': {
|
||||
useAction: '{{ cm.useCancelAction }}',
|
||||
},
|
||||
},
|
||||
submit: {
|
||||
title: '{{t("Submit")}}',
|
||||
'x-component': 'Action',
|
||||
'x-component-props': {
|
||||
type: 'primary',
|
||||
useAction: useUpdateConfigAction,
|
||||
},
|
||||
},
|
||||
title: '配置节点',
|
||||
'x-component': 'Action.Drawer',
|
||||
'x-decorator': 'Form',
|
||||
'x-decorator-props': {
|
||||
useValues(options) {
|
||||
const node = useNodeContext();
|
||||
return useRequest(() => {
|
||||
return Promise.resolve({ data: node.config });
|
||||
}, options);
|
||||
}
|
||||
},
|
||||
} as ISchema
|
||||
properties: {
|
||||
...instruction.fieldset,
|
||||
actions: {
|
||||
type: 'void',
|
||||
'x-component': 'Action.Drawer.Footer',
|
||||
properties: {
|
||||
cancel: {
|
||||
title: '{{t("Cancel")}}',
|
||||
'x-component': 'Action',
|
||||
'x-component-props': {
|
||||
useAction: '{{ cm.useCancelAction }}',
|
||||
},
|
||||
},
|
||||
submit: {
|
||||
title: '{{t("Submit")}}',
|
||||
'x-component': 'Action',
|
||||
'x-component-props': {
|
||||
type: 'primary',
|
||||
useAction: useUpdateConfigAction,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ISchema
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
: {})
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
@ -11,7 +11,7 @@ import { useFlowContext } from '../WorkflowCanvas';
|
||||
import { Operand, parseStringValue, VariableTypes, VariableTypesContext, BaseTypeSet } from '../calculators';
|
||||
|
||||
export default {
|
||||
title: '数据查询',
|
||||
title: '查询',
|
||||
type: 'query',
|
||||
group: 'model',
|
||||
fieldset: {
|
||||
|
@ -72,11 +72,15 @@ export default {
|
||||
const collection = collections.find(item => item.name === workflow.config.collection) ?? { fields: [] };
|
||||
|
||||
return (
|
||||
<Select value={options?.path.replace(/^data\./, '')} placeholder="选择字段" onChange={path => {
|
||||
onChange({ type, options: { ...options, path: `data.${path}` } });
|
||||
}}>
|
||||
<Select
|
||||
placeholder="选择字段"
|
||||
value={options?.path?.replace(/^data\./, '')}
|
||||
onChange={(path) => {
|
||||
onChange({ type, options: { ...options, path: `data.${path}` } });
|
||||
}}
|
||||
>
|
||||
{collection.fields
|
||||
.filter(field => BaseTypeSet.has(field.uiSchema.type))
|
||||
.filter(field => BaseTypeSet.has(field?.uiSchema?.type))
|
||||
.map(field => (
|
||||
<Select.Option key={field.name} value={field.name}>{t(field.uiSchema.title)}</Select.Option>
|
||||
))}
|
||||
|
Loading…
Reference in New Issue
Block a user