Browse Source

feat: schemaForm简易版

master
suanmei 5 years ago
committed by 拾邑
parent
commit
faf2d7dfa5
  1. 2
      packages/core/package.json
  2. 69
      packages/core/src/components/schema-form.tsx
  3. 161
      packages/core/src/components/setting.tsx
  4. 20
      packages/core/src/components/sidebar.tsx
  5. 45
      packages/core/src/data/cells.ts

2
packages/core/package.json

@ -30,7 +30,7 @@
"prepublishOnly": "node scripts/prepublishOnly.js", "prepublishOnly": "node scripts/prepublishOnly.js",
"declare-type": "tsc --emitDeclarationOnly", "declare-type": "tsc --emitDeclarationOnly",
"build": "rollup -c & npm run declare-type", "build": "rollup -c & npm run declare-type",
"watch": "watch 'rollup -c' ./src" "watch": "watch 'npm run build' ./src"
}, },
"bugs": { "bugs": {
"url": "https://github.com/suanmei/iMove/issues" "url": "https://github.com/suanmei/iMove/issues"

69
packages/core/src/components/schema-form.tsx

@ -0,0 +1,69 @@
import * as React from 'react';
import { Form, Input, InputNumber } from 'antd';
const { Item } = Form;
const labelCol = { span: 7 };
export interface SchemaFormProps {
schema: any;
data: any;
}
export interface SchemaFormState {
data: any;
}
class SchemaForm extends React.Component<SchemaFormProps, SchemaFormState> {
constructor(props: SchemaFormProps) {
super(props);
this.state = {
data: props.data,
};
}
changeValue = (e: React.ChangeEvent<HTMLInputElement>, key: string): void => {
const { data } = this.state;
const value = e.target.value.trim();
data[key] = value;
this.setState({ data });
};
changeNumValue = (value: number | undefined, key: string): void => {
const { data } = this.state;
data[key] = value;
this.setState({ data });
};
render(): JSX.Element {
const { data } = this.state;
const {
schema: { properties },
} = this.props;
return (
<Form labelCol={labelCol} initialValues={data}>
{Object.keys(properties).map((key) => (
<Item label={properties[key].title} name={properties[key].title}>
{properties[key].type === 'string' ? (
<Input
onChange={(e): void => {
this.changeValue(e, key);
}}
/>
) : (
<InputNumber
onChange={(value): void => {
this.changeNumValue(value, key);
}}
/>
)}
</Item>
))}
</Form>
);
}
}
export default SchemaForm;

161
packages/core/src/components/setting.tsx

@ -1,15 +1,18 @@
/** @jsx jsx */ /** @jsx jsx */
import { useState } from 'react'; import { Component } from 'react';
import { jsx, css } from '@emotion/core'; import { jsx, css } from '@emotion/core';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { Graph, Cell } from '@antv/x6'; import { Graph, Cell } from '@antv/x6';
import { Collapse, Form, Input } from 'antd'; import { Collapse, Form, Input } from 'antd';
import SchemaForm from './schema-form';
import 'antd/lib/form/style'; import 'antd/lib/form/style';
import 'antd/lib/input/style'; import 'antd/lib/input/style';
const { Panel } = Collapse; const { Panel } = Collapse;
const { Item } = Form; const { Item } = Form;
const labelCol = { span: 7 };
const Header = styled.h3` const Header = styled.h3`
margin-bottom: 0; margin-bottom: 0;
padding-left: 20px; padding-left: 20px;
@ -36,55 +39,123 @@ interface SettingProps {
graph: Graph; graph: Graph;
} }
const Setting = ({ graph }: SettingProps): JSX.Element => { interface SettingState {
const [cell, setCell] = useState<Cell<any> | null>(null); cell: Cell<any> | null;
}
class Setting extends Component<SettingProps, SettingState> {
constructor(props: SettingProps) {
super(props);
graph.on('selection:changed', () => { this.state = {
const cells = graph.getSelectedCells(); cell: null,
setCell(cells.length > 0 ? cells[0] : null); };
});
let cellType = ''; const { graph } = this.props;
graph.on('selection:changed', () => {
const cells = graph.getSelectedCells();
if (cells.length === 0) {
this.setState({ cell: null });
return;
}
if (cell) { const cell = cells[0];
if (cell.isNode()) {
cellType = cell.data.type.toUpperCase(); if (cell.isEdge()) {
cell.data = {};
}
this.setState({ cell });
});
}
render(): JSX.Element {
const { graph } = this.props;
const { cell } = this.state;
let cellType = '';
if (cell) {
if (cell.isNode()) {
cellType = cell.data.type.toUpperCase();
} else {
cellType = 'EDGE';
}
} else { } else {
cellType = 'EDGE'; cellType = 'FLOW';
} }
} else {
cellType = 'FLOW';
}
return ( return (
<div <div
css={css` css={css`
height: 100%; height: 100%;
overflow: auto; overflow: auto;
border-left: 1px solid #ddd; border-left: 1px solid #ddd;
`} `}
> >
<Header>{cellType}</Header> <Header>{cellType}</Header>
{cell && cell.isNode() && ['decision', 'action'].includes(cell.data.type) && ( {cell && !['start', 'end'].includes(cell.data.type) && (
<SettingCollapse defaultActiveKey={['general']}> <SettingCollapse
<Panel header="General" key="general"> defaultActiveKey={['general', 'event', 'input', 'output']}
<Form initialValues={{ label: cell.data.label }}> key={cell && cell.id ? cell.id : ''}
<Item label="名称" name="label"> >
<Input <Panel header="General" key="general">
onChange={(e): void => { <Form labelCol={labelCol} initialValues={{ label: cell.data.label }}>
console.log(`first: ${cell.data.label}`); <Item label="名称" name="label">
cell.data.label = e.target.value.trim(); <Input
console.log(`then: ${cell.data.label}`); onChange={(e): void => {
graph.setCellData(cell, cell.data); cell.data.label = e.target.value.trim();
}} graph.setCellData(cell, cell.data);
/> }}
</Item> />
</Form> </Item>
</Panel> </Form>
</SettingCollapse> </Panel>
)} {/* <Panel header="Event" key="event">
</div> <Form
); labelCol={labelCol}
}; initialValues={{ event: cell.data && cell.data.data && cell.data.data.event }}
>
<Item label="触发事件" name="event">
<Input
onChange={(e): void => {
if (!cell.data.data) {
cell.data.data = {};
}
cell.data.data.event = e.target.value.trim();
graph.setCellData(cell, cell.data);
}}
/>
</Item>
</Form>
</Panel> */}
{cell.data && cell.data.schema && (
<Panel header="Input" key="input">
<SchemaForm schema={cell.data.schema} data={cell.data.data} />
</Panel>
)}
<Panel header="Output" key="output">
<Form
labelCol={labelCol}
initialValues={{ event: cell.data && cell.data.data && cell.data.data.contextKey }}
>
<Item label="存储字段" name="contextKey">
<Input
onChange={(e): void => {
if (!cell.data.data) {
cell.data.data = {};
}
cell.data.data.contextKey = e.target.value.trim();
graph.setCellData(cell, cell.data);
}}
/>
</Item>
</Form>
</Panel>
</SettingCollapse>
)}
</div>
);
}
}
export default Setting; export default Setting;

20
packages/core/src/components/sidebar.tsx

@ -4,7 +4,7 @@ import { jsx, css } from '@emotion/core';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { Graph } from '@antv/x6'; import { Graph } from '@antv/x6';
import { Collapse } from 'antd'; import { Collapse } from 'antd';
import { generals, DataItem } from '../data/cells'; import { generals, gists, DataItem } from '../data/cells';
import patchDnd from '../utils/patch-dnd'; import patchDnd from '../utils/patch-dnd';
import Cells from './cells'; import Cells from './cells';
import 'antd/lib/collapse/style'; import 'antd/lib/collapse/style';
@ -79,10 +79,14 @@ const CellWrapper = ({ data, children }: { data: DataItem; children: ReactNode }
const Sidebar = ({ graph }: SidebarProps): JSX.Element => { const Sidebar = ({ graph }: SidebarProps): JSX.Element => {
const generalRef = useRef<HTMLDivElement>(null); const generalRef = useRef<HTMLDivElement>(null);
const gistRef = useRef<HTMLDivElement>(null);
useEffect(() => { useEffect(() => {
const generalContainer = generalRef.current; const generalContainer = generalRef.current;
patchDnd(generalContainer, graph, generals); patchDnd(generalContainer, graph, generals);
const gistContainer = gistRef.current;
patchDnd(gistContainer, graph, gists);
}); });
return ( return (
@ -93,7 +97,7 @@ const Sidebar = ({ graph }: SidebarProps): JSX.Element => {
border-right: 1px solid #ddd; border-right: 1px solid #ddd;
`} `}
> >
<ToolCollapse defaultActiveKey={['general']}> <ToolCollapse defaultActiveKey={['general', 'gist']}>
<ToolPanel header="General" key="general"> <ToolPanel header="General" key="general">
<div ref={generalRef}> <div ref={generalRef}>
{generals.map((cell) => { {generals.map((cell) => {
@ -106,6 +110,18 @@ const Sidebar = ({ graph }: SidebarProps): JSX.Element => {
})} })}
</div> </div>
</ToolPanel> </ToolPanel>
<ToolPanel header="业务元件" key="gist">
<div ref={gistRef}>
{gists.map((cell) => {
const Cell = Cells[cell.type];
return (
<CellWrapper key={`${cell.type}${cell.label}`} data={cell}>
<Cell />
</CellWrapper>
);
})}
</div>
</ToolPanel>
</ToolCollapse> </ToolCollapse>
</div> </div>
); );

45
packages/core/src/data/cells.ts

@ -12,6 +12,7 @@ export interface DataItem {
style: Style; style: Style;
data?: any; data?: any;
isEdge?: boolean; isEdge?: boolean;
schema?: any;
} }
export const generals: DataItem[] = [ export const generals: DataItem[] = [
@ -25,30 +26,56 @@ export const generals: DataItem[] = [
}, },
}, },
{ {
label: 'Action', label: 'End Event',
type: 'action', type: 'end',
style: { style: {
width: 48, width: 20,
height: 30, height: 20,
scale: 2, scale: 2,
}, },
}, },
];
export const gists: DataItem[] = [
{ {
label: 'End Event', label: '查询库存',
type: 'end', type: 'action',
style: { style: {
width: 20, width: 48,
height: 20, height: 30,
scale: 2, scale: 2,
}, },
data: {
code: '',
dependencies: [],
},
schema: {
type: 'object',
properties: {
activity: {
type: 'string',
title: 'activity',
},
initAmount: {
type: 'string',
title: 'initAmount',
},
},
required: ['initAmount', 'activity'],
title: '参数',
},
}, },
{ {
label: 'Decision', label: '判断是否登录',
type: 'decision', type: 'decision',
style: { style: {
width: 48, width: 48,
height: 30, height: 30,
scale: 2, scale: 2,
}, },
data: {
code: '',
dependencies: [],
},
}, },
]; ];

Loading…
Cancel
Save