mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-03-04 09:15:16 +00:00
feat: 数据源面板
This commit is contained in:
parent
56eaff52c8
commit
47f55cafce
@ -13,7 +13,72 @@
|
|||||||
"list": [
|
"list": [
|
||||||
{
|
{
|
||||||
"type": "http",
|
"type": "http",
|
||||||
"id": "http1",
|
"id": "请求商家数据,是一个 HTTP 请求,是一个 HTTP 请求,是一个 HTTP 请求",
|
||||||
|
"isInit": true,
|
||||||
|
"options": {
|
||||||
|
"uri": "https://www.taobao.com",
|
||||||
|
"params": {
|
||||||
|
"a": 1,
|
||||||
|
"b": true,
|
||||||
|
"c": "3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "http",
|
||||||
|
"id": "请求商家数据2,是一个 HTTP 请求,是一个 HTTP 请求,是一个 HTTP 请求",
|
||||||
|
"isInit": true,
|
||||||
|
"options": {
|
||||||
|
"uri": "https://www.taobao.com",
|
||||||
|
"params": {
|
||||||
|
"a": 1,
|
||||||
|
"b": true,
|
||||||
|
"c": "3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "http",
|
||||||
|
"id": "请求商家数据3,是一个 HTTP 请求,是一个 HTTP 请求,是一个 HTTP 请求",
|
||||||
|
"isInit": true,
|
||||||
|
"options": {
|
||||||
|
"uri": "https://www.taobao.com",
|
||||||
|
"params": {
|
||||||
|
"a": 1,
|
||||||
|
"b": true,
|
||||||
|
"c": "3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "http",
|
||||||
|
"id": "请求商家数据4,是一个 HTTP 请求,是一个 HTTP 请求,是一个 HTTP 请求",
|
||||||
|
"isInit": true,
|
||||||
|
"options": {
|
||||||
|
"uri": "https://www.taobao.com",
|
||||||
|
"params": {
|
||||||
|
"a": 1,
|
||||||
|
"b": true,
|
||||||
|
"c": "3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "http",
|
||||||
|
"id": "请求商家数据5,是一个 HTTP 请求,是一个 HTTP 请求,是一个 HTTP 请求",
|
||||||
|
"isInit": false,
|
||||||
|
"options": {
|
||||||
|
"uri": "https://www.taobao.com",
|
||||||
|
"params": {
|
||||||
|
"a": 1,
|
||||||
|
"b": true,
|
||||||
|
"c": "3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "http",
|
||||||
|
"id": "请求商家数据6,是一个 HTTP 请求,是一个 HTTP 请求,是一个 HTTP 请求",
|
||||||
"isInit": true,
|
"isInit": true,
|
||||||
"options": {
|
"options": {
|
||||||
"uri": "https://www.taobao.com",
|
"uri": "https://www.taobao.com",
|
||||||
|
|||||||
0
packages/plugin-datasource-pane/CHANGELOG.md
Normal file
0
packages/plugin-datasource-pane/CHANGELOG.md
Normal file
@ -1,26 +1,10 @@
|
|||||||
TODO
|
## 低代码引擎 - 数据源面板插件
|
||||||
---
|
|
||||||
|
|
||||||
* 多语言
|
对页面的数据源进行管理(新建,编辑,导入)。
|
||||||
* [later]表达式和其他类型的切换
|
|
||||||
* 现有场景代码的兼容
|
|
||||||
* class publich method bind issue
|
|
||||||
* ICON
|
|
||||||
* 支持变量
|
|
||||||
|
|
||||||
## 数据源面板
|
|
||||||
|
|
||||||
数据源管理
|
|
||||||
|
|
||||||
* 新建
|
|
||||||
* 编辑
|
|
||||||
* 导入
|
|
||||||
* 指定数据源类型
|
|
||||||
* 定制数据源导入插件
|
|
||||||
|
|
||||||
## 数据源类型定义
|
## 数据源类型定义
|
||||||
|
|
||||||
内置变量,http 和 mtop 类型,支持传入自定义类型。
|
内置 fetch 和 mtop 类型,支持传入自定义类型。
|
||||||
|
|
||||||
```
|
```
|
||||||
type DataSourceType = {
|
type DataSourceType = {
|
||||||
@ -29,9 +13,7 @@ type DataSourceType = {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
数据源类型需要在集团规范约束下扩展。
|
数据源类型需要在集团规范约束下扩展。目前只允许在 options 下添加扩展字段。
|
||||||
|
|
||||||
目前只允许在 options 下添加扩展字段。
|
|
||||||
|
|
||||||
比如 mtop 类型,需要添加 options.v (版本)字段。
|
比如 mtop 类型,需要添加 options.v (版本)字段。
|
||||||
|
|
||||||
@ -56,16 +38,8 @@ interface DataSourcePaneImportPluginComponentProps extends DataSourcePaneImportP
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## 问题
|
|
||||||
|
|
||||||
* 变量,上下文放数据源里管理是否合适
|
|
||||||
* mockUrl 和 mockData
|
|
||||||
* 设计器的设计语言无法统一
|
|
||||||
|
|
||||||
## 插件开发
|
## 插件开发
|
||||||
|
|
||||||
<https://yuque.antfin-inc.com/ali-lowcode/docs/ip4awq>
|
[https://yuque.antfin-inc.com/ali-lowcode/docs/ip4awq](插件开发文档)。
|
||||||
|
|
||||||
## node 版本
|
本地开发需要在 v14.4.0 的 node 环境下进行。
|
||||||
|
|
||||||
v14.4.0
|
|
||||||
|
|||||||
18
packages/plugin-datasource-pane/TODO.md
Normal file
18
packages/plugin-datasource-pane/TODO.md
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
TODO
|
||||||
|
---
|
||||||
|
|
||||||
|
* 多语言
|
||||||
|
* ICON
|
||||||
|
* 支持变量
|
||||||
|
* 定制样式
|
||||||
|
* 不使用 bind
|
||||||
|
* 表达式 setter 的联想
|
||||||
|
* [later]表达式和其他类型的切换
|
||||||
|
* 变量,上下文的提案
|
||||||
|
* mock 的提案
|
||||||
|
|
||||||
|
## 问题
|
||||||
|
|
||||||
|
* 变量,上下文放数据源里管理是否合适
|
||||||
|
* mockUrl 和 mockData
|
||||||
|
* 设计器的设计语言无法统一
|
||||||
@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
"plugins": [
|
"plugins": [
|
||||||
[
|
"build-plugin-component",
|
||||||
"build-plugin-component"
|
"build-plugin-fusion"
|
||||||
]
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
// @todo schema default
|
// @todo schema default
|
||||||
import React, { PureComponent, ReactElement, FC } from 'react';
|
import React, { PureComponent, ReactElement, FC } from 'react';
|
||||||
|
import { Button } from '@alifd/next';
|
||||||
import { SchemaForm, FormButtonGroup, Submit } from '@formily/next';
|
import { SchemaForm, FormButtonGroup, Submit } from '@formily/next';
|
||||||
import { ArrayTable, Input, Switch, NumberPicker } from '@formily/next-components';
|
import { ArrayTable, Input, Switch, NumberPicker } from '@formily/next-components';
|
||||||
import _isPlainObject from 'lodash/isPlainObject';
|
import _isPlainObject from 'lodash/isPlainObject';
|
||||||
@ -164,8 +165,6 @@ export class DataSourceForm extends PureComponent<DataSourceFormProps, DataSourc
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
debugger;
|
|
||||||
|
|
||||||
if (_get(formSchema, 'properties.options.properties.params')) {
|
if (_get(formSchema, 'properties.options.properties.params')) {
|
||||||
formSchema.properties.options.properties.params = {
|
formSchema.properties.options.properties.params = {
|
||||||
...formSchema.properties.options.properties.params,
|
...formSchema.properties.options.properties.params,
|
||||||
@ -247,7 +246,7 @@ export class DataSourceForm extends PureComponent<DataSourceFormProps, DataSourc
|
|||||||
const { dataSource } = this.props;
|
const { dataSource } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="lowcode-plugin-datasource-pane-datasource">
|
<div className="lowcode-plugin-datasource-form">
|
||||||
<SchemaForm
|
<SchemaForm
|
||||||
onSubmit={this.handleFormSubmit}
|
onSubmit={this.handleFormSubmit}
|
||||||
components={{
|
components={{
|
||||||
@ -258,13 +257,14 @@ export class DataSourceForm extends PureComponent<DataSourceFormProps, DataSourc
|
|||||||
Switch,
|
Switch,
|
||||||
JSFunction,
|
JSFunction,
|
||||||
}}
|
}}
|
||||||
labelCol={3}
|
labelCol={4}
|
||||||
wrapperCol={21}
|
wrapperCol={19}
|
||||||
schema={this.deriveSchema()}
|
schema={this.deriveSchema()}
|
||||||
initialValues={this.deriveInitialData(dataSource)}
|
initialValues={this.deriveInitialData(dataSource)}
|
||||||
>
|
>
|
||||||
<FormButtonGroup offset={7}>
|
<FormButtonGroup offset={4}>
|
||||||
<Submit>提交</Submit>
|
<Submit>提交</Submit>
|
||||||
|
<Button onClick={this.handleCancel}>取消</Button>
|
||||||
</FormButtonGroup>
|
</FormButtonGroup>
|
||||||
</SchemaForm>
|
</SchemaForm>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -0,0 +1,7 @@
|
|||||||
|
.param-value {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
.param-value-type {
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import React, { PureComponent, ReactElement, FC } from 'react';
|
import React, { PureComponent, ReactElement, FC } from 'react';
|
||||||
import { Button, Input, Radio, NumberPicker, Switch } from '@alifd/next';
|
import { Select, Input, Radio, NumberPicker, Switch } from '@alifd/next';
|
||||||
import { connect } from '@formily/react-schema-renderer';
|
import { connect } from '@formily/react-schema-renderer';
|
||||||
import _isPlainObject from 'lodash/isPlainObject';
|
import _isPlainObject from 'lodash/isPlainObject';
|
||||||
import _isArray from 'lodash/isArray';
|
import _isArray from 'lodash/isArray';
|
||||||
@ -10,21 +10,37 @@ import _get from 'lodash/get';
|
|||||||
import _tap from 'lodash/tap';
|
import _tap from 'lodash/tap';
|
||||||
import { ExpressionSetter } from '@ali/lowcode-editor-setters';
|
import { ExpressionSetter } from '@ali/lowcode-editor-setters';
|
||||||
|
|
||||||
|
import './param-value.scss';
|
||||||
|
|
||||||
const { Group: RadioGroup } = Radio;
|
const { Group: RadioGroup } = Radio;
|
||||||
|
|
||||||
|
type ParamValueType = 'string' | 'number' | 'boolean' | 'expression';
|
||||||
|
|
||||||
export interface ParamValueProps {
|
export interface ParamValueProps {
|
||||||
className: string;
|
className: string;
|
||||||
value: any;
|
value: any;
|
||||||
onChange?: () => void;
|
onChange?: () => void;
|
||||||
|
types: ParamValueType[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ParamValueState {
|
export interface ParamValueState {
|
||||||
type: 'string' | 'number' | 'boolean' | '';
|
type: 'string' | 'number' | 'boolean' | '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const TYPE_LABEL_MAP = {
|
||||||
|
string: '字符串',
|
||||||
|
number: '数字',
|
||||||
|
boolean: '布尔',
|
||||||
|
expression: '表达式',
|
||||||
|
};
|
||||||
|
|
||||||
class ParamValueComp extends PureComponent<ParamValueProps, ParamValueState> {
|
class ParamValueComp extends PureComponent<ParamValueProps, ParamValueState> {
|
||||||
static isFieldComponent = true;
|
static isFieldComponent = true;
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
types: ['string', 'boolean', 'number', 'expression'],
|
||||||
|
};
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
type: '',
|
type: '',
|
||||||
};
|
};
|
||||||
@ -48,7 +64,7 @@ class ParamValueComp extends PureComponent<ParamValueProps, ParamValueState> {
|
|||||||
// @todo 需要再 bind 一次?
|
// @todo 需要再 bind 一次?
|
||||||
handleChange = (value) => {
|
handleChange = (value) => {
|
||||||
this.props?.onChange(value);
|
this.props?.onChange(value);
|
||||||
}
|
};
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
if (this.props.value !== prevProps.value) {
|
if (this.props.value !== prevProps.value) {
|
||||||
@ -78,19 +94,46 @@ class ParamValueComp extends PureComponent<ParamValueProps, ParamValueState> {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
renderTypeSelect = () => {
|
||||||
|
const { type } = this.state;
|
||||||
|
const { types } = this.props;
|
||||||
|
|
||||||
|
if (_isArray(types) && types.length > 2) {
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
className="param-value-type"
|
||||||
|
dataSource={types.map((item) => ({
|
||||||
|
label: TYPE_LABEL_MAP[item],
|
||||||
|
value: item,
|
||||||
|
}))}
|
||||||
|
value={type}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (_isArray(types) && types.length > 1) {
|
||||||
|
return (
|
||||||
|
<RadioGroup
|
||||||
|
className="param-value-type"
|
||||||
|
shape="button"
|
||||||
|
size="small"
|
||||||
|
onChange={this.handleTypeChange}
|
||||||
|
value={type}
|
||||||
|
>
|
||||||
|
{types.map((item) => (
|
||||||
|
<Radio value={item}>TYPE_LABEL_MAP[item]</Radio>
|
||||||
|
))}
|
||||||
|
</RadioGroup>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { type } = this.state;
|
const { type } = this.state;
|
||||||
const { value } = this.props;
|
const { value } = this.props;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className="param-value">
|
||||||
{
|
{this.renderTypeSelect()}
|
||||||
<RadioGroup shape="button" size="small" onChange={this.handleTypeChange}>
|
|
||||||
<Radio value="string">字符串</Radio>
|
|
||||||
<Radio value="boolean">布尔</Radio>
|
|
||||||
<Radio value="number">数字</Radio>
|
|
||||||
<Radio value="expression">表达式</Radio>
|
|
||||||
</RadioGroup>
|
|
||||||
}
|
|
||||||
{type === 'string' && <Input onChange={this.handleChange.bind(this)} value={value} />}
|
{type === 'string' && <Input onChange={this.handleChange.bind(this)} value={value} />}
|
||||||
{type === 'boolean' && <Switch onChange={this.handleChange.bind(this)} checked={value} />}
|
{type === 'boolean' && <Switch onChange={this.handleChange.bind(this)} checked={value} />}
|
||||||
{type === 'number' && <NumberPicker onChange={this.handleChange.bind(this)} value={value} />}
|
{type === 'number' && <NumberPicker onChange={this.handleChange.bind(this)} value={value} />}
|
||||||
|
|||||||
15
packages/plugin-datasource-pane/src/import-plugins/code.scss
Normal file
15
packages/plugin-datasource-pane/src/import-plugins/code.scss
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
.lowcode-plugin-datasource-import-plugin-code {
|
||||||
|
height: unquote("calc(100vh - 48px - 48px - 42px)");
|
||||||
|
overflow: auto;
|
||||||
|
.error-msg {
|
||||||
|
line-height: 24px;
|
||||||
|
color: #f60;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.btns {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
.next-btn {
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -14,6 +14,8 @@ import { DataSourceConfig } from '@ali/lowcode-types';
|
|||||||
import Ajv from 'ajv';
|
import Ajv from 'ajv';
|
||||||
import { DataSourcePaneImportPluginComponentProps } from '../types';
|
import { DataSourcePaneImportPluginComponentProps } from '../types';
|
||||||
|
|
||||||
|
import './code.scss';
|
||||||
|
|
||||||
export interface DataSourceImportPluginCodeProps extends DataSourcePaneImportPluginComponentProps {
|
export interface DataSourceImportPluginCodeProps extends DataSourcePaneImportPluginComponentProps {
|
||||||
defaultValue?: DataSourceConfig[];
|
defaultValue?: DataSourceConfig[];
|
||||||
}
|
}
|
||||||
@ -115,11 +117,11 @@ export class DataSourceImportPluginCode extends PureComponent<
|
|||||||
const { code, isCodeValid } = this.state;
|
const { code, isCodeValid } = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className="lowcode-plugin-datasource-import-plugin-code">
|
||||||
<MonacoEditor
|
<MonacoEditor
|
||||||
theme="vs-dark"
|
theme="vs-dark"
|
||||||
width={800}
|
width={800}
|
||||||
height={600}
|
height={400}
|
||||||
defaultValue={code}
|
defaultValue={code}
|
||||||
language="json"
|
language="json"
|
||||||
onChange={this.handleEditorChange}
|
onChange={this.handleEditorChange}
|
||||||
@ -127,10 +129,10 @@ export class DataSourceImportPluginCode extends PureComponent<
|
|||||||
formatOnType
|
formatOnType
|
||||||
formatOnPaste
|
formatOnPaste
|
||||||
/>
|
/>
|
||||||
{!isCodeValid && <p>格式有误</p>}
|
{!isCodeValid && <p className="error-msg">格式有误</p>}
|
||||||
<p>
|
<p className="btns">
|
||||||
<Button onClick={onCancel}>取消</Button>
|
<Button onClick={onCancel}>取消</Button>
|
||||||
<Button onClick={this.handleComplete}>确认</Button>
|
<Button type="primary" onClick={this.handleComplete}>确认</Button>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -12,7 +12,86 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.lowcode-plugin-datasource-pane-list {
|
.lowcode-plugin-datasource-pane-list {
|
||||||
.next-virtual-list-wrapper {
|
margin: 8px;
|
||||||
min-height: 400px;
|
.next-search {
|
||||||
|
width: 100%;
|
||||||
|
.next-search-left {
|
||||||
|
height: 28px !important;
|
||||||
|
border-top-left-radius: 3px;
|
||||||
|
border-bottom-left-radius: 3px;
|
||||||
|
.next-before {
|
||||||
|
height: 28px !important;
|
||||||
|
.next-select {
|
||||||
|
height: 28px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.next-search-input {
|
||||||
|
height: 28px !important;
|
||||||
|
input {
|
||||||
|
height: 28px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.next-input {
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.next-after {
|
||||||
|
// height: 28px !important;
|
||||||
|
.next-btn {
|
||||||
|
height: 30px !important;
|
||||||
|
border-top-right-radius: 3px;
|
||||||
|
border-bottom-right-radius: 3px;
|
||||||
|
.next-icon:before {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.datasource-list {
|
||||||
|
margin-top: 8px;
|
||||||
|
height: unquote("calc(100vh - 48px - 48px - 42px - 28px - 8px - 8px)");
|
||||||
|
overflow: auto;
|
||||||
|
.next-virtual-list-wrapper > div > ul > li {
|
||||||
|
border-top: 1px solid #ddd;
|
||||||
|
&:first-child {
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.datasource-item {
|
||||||
|
margin: 8px;
|
||||||
|
.datasource-item-title {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
height: 28px;
|
||||||
|
.datasource-item-id {
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.next-btn {
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.datasource-item-desc {
|
||||||
|
.next-tag {
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.lowcode-plugin-datasource-form {
|
||||||
|
height: unquote("calc(100vh - 48px - 48px - 42px)");
|
||||||
|
overflow: auto;
|
||||||
|
.next-form-item {
|
||||||
|
.next-form-item-control {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,8 @@ import { DataSourcePane } from './pane';
|
|||||||
import { DataSourcePaneImportPlugin, DataSourceType } from './types';
|
import { DataSourcePaneImportPlugin, DataSourceType } from './types';
|
||||||
import { DataSourceImportPluginCode } from './import-plugins';
|
import { DataSourceImportPluginCode } from './import-plugins';
|
||||||
|
|
||||||
|
import './index.scss';
|
||||||
|
|
||||||
export { DataSourceImportPluginCode };
|
export { DataSourceImportPluginCode };
|
||||||
|
|
||||||
const PLUGIN_NAME = 'dataSourcePane';
|
const PLUGIN_NAME = 'dataSourcePane';
|
||||||
|
|||||||
@ -64,57 +64,77 @@ export default class DataSourceList extends PureComponent<DataSourceListProps, D
|
|||||||
?.filter((item) => (keyword ? item.id.indexOf(keyword) !== -1 : true))
|
?.filter((item) => (keyword ? item.id.indexOf(keyword) !== -1 : true))
|
||||||
?.map((item) => (
|
?.map((item) => (
|
||||||
<li key={item.id}>
|
<li key={item.id}>
|
||||||
<Balloon
|
<div className="datasource-item">
|
||||||
trigger={
|
<div className="datasource-item-title">
|
||||||
<div>
|
<div className="datasource-item-id" title={item.id}>
|
||||||
<Tag size="small">{item.type}</Tag>
|
|
||||||
<Tag size="small">{item.isInit ? '自动' : '手动'}</Tag>
|
|
||||||
{item.id}
|
{item.id}
|
||||||
<Button onClick={this.handleEditDataSource.bind(this, item.id)}>编辑</Button>
|
|
||||||
<Button onClick={this.handleDuplicateDataSource.bind(this, item.id)}>复制</Button>
|
|
||||||
<Button onClick={this.handleRemoveDataSource.bind(this, item.id)}>删除</Button>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
<Balloon
|
||||||
align="r"
|
trigger={<Button size="small">详情</Button>}
|
||||||
alignEdge
|
align="b"
|
||||||
triggerType="hover"
|
alignEdge
|
||||||
style={{ width: 300 }}
|
triggerType="hover"
|
||||||
>
|
style={{ width: 300 }}
|
||||||
<Table
|
>
|
||||||
dataSource={_tap(Object.keys(item.options || {}).reduce<TableRow[]>((acc, cur) => {
|
<Table
|
||||||
// @todo 这里的 ts 处理得不好
|
dataSource={_tap(
|
||||||
if (_isPlainObject(item.options[cur])) {
|
Object.keys(item.options || {}).reduce<TableRow[]>((acc, cur) => {
|
||||||
Object.keys(item?.options?.[cur] || {}).forEach((curInOption) => {
|
// @todo 这里的 ts 处理得不好
|
||||||
acc.push({
|
if (_isPlainObject(item.options[cur])) {
|
||||||
label: `${cur}.${curInOption}`,
|
Object.keys(item?.options?.[cur] || {}).forEach((curInOption) => {
|
||||||
value: (item?.options?.[cur] as any)?.[curInOption],
|
acc.push({
|
||||||
});
|
label: `${cur}.${curInOption}`,
|
||||||
});
|
value: (item?.options?.[cur] as any)?.[curInOption],
|
||||||
} else if (!_isNil(item.options[cur])) {
|
});
|
||||||
// @todo 排除 null
|
});
|
||||||
acc.push({
|
} else if (!_isNil(item.options[cur])) {
|
||||||
label: cur,
|
// @todo 排除 null
|
||||||
value: item.options[cur],
|
acc.push({
|
||||||
});
|
label: cur,
|
||||||
}
|
value: item.options[cur],
|
||||||
return acc;
|
});
|
||||||
}, []), console.log)}
|
}
|
||||||
>
|
return acc;
|
||||||
<TableCol title="" dataIndex="label" />
|
}, []),
|
||||||
<TableCol
|
console.log,
|
||||||
title=""
|
)}
|
||||||
dataIndex="value"
|
>
|
||||||
cell={(val: any) => (
|
<TableCol title="" dataIndex="label" />
|
||||||
<div>
|
<TableCol
|
||||||
<Tag>
|
title=""
|
||||||
{_isBoolean(val) ? 'bool' : _isNumber(val) ? 'number' : _isPlainObject(val) ? 'obj' : 'string'}
|
dataIndex="value"
|
||||||
</Tag>
|
cell={(val: any) => (
|
||||||
{val.toString()}
|
<div>
|
||||||
</div>
|
<Tag>
|
||||||
)}
|
{_isBoolean(val)
|
||||||
/>
|
? 'bool'
|
||||||
</Table>
|
: _isNumber(val)
|
||||||
</Balloon>
|
? 'number'
|
||||||
|
: _isPlainObject(val)
|
||||||
|
? 'obj'
|
||||||
|
: 'string'}
|
||||||
|
</Tag>
|
||||||
|
{val.toString()}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Table>
|
||||||
|
</Balloon>
|
||||||
|
<Button size="small" onClick={this.handleEditDataSource.bind(this, item.id)}>
|
||||||
|
编辑
|
||||||
|
</Button>
|
||||||
|
<Button size="small" onClick={this.handleDuplicateDataSource.bind(this, item.id)}>
|
||||||
|
复制
|
||||||
|
</Button>
|
||||||
|
<Button size="small" onClick={this.handleRemoveDataSource.bind(this, item.id)}>
|
||||||
|
删除
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div className="datasource-item-desc">
|
||||||
|
<Tag size="small">{item.type}</Tag>
|
||||||
|
<Tag size="small">{item.isInit ? '自动' : '手动'}</Tag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
)) || []
|
)) || []
|
||||||
);
|
);
|
||||||
@ -136,7 +156,9 @@ export default class DataSourceList extends PureComponent<DataSourceListProps, D
|
|||||||
}))}
|
}))}
|
||||||
onFilterChange={this.handleSearchFilterChange}
|
onFilterChange={this.handleSearchFilterChange}
|
||||||
/>
|
/>
|
||||||
<VirtualList>{this.deriveListDataSource()}</VirtualList>
|
<div className="datasource-list">
|
||||||
|
<VirtualList>{this.deriveListDataSource()}</VirtualList>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
*/
|
*/
|
||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import { DataSource, DataSourceConfig } from '@ali/lowcode-types';
|
import { DataSource, DataSourceConfig } from '@ali/lowcode-types';
|
||||||
import { Tab, Button, MenuButton, Message } from '@alifd/next';
|
import { Tab, Button, MenuButton, Message, Dialog } from '@alifd/next';
|
||||||
import _cloneDeep from 'lodash/cloneDeep';
|
import _cloneDeep from 'lodash/cloneDeep';
|
||||||
import _uniqueId from 'lodash/uniqueId';
|
import _uniqueId from 'lodash/uniqueId';
|
||||||
import _startsWith from 'lodash/startsWith';
|
import _startsWith from 'lodash/startsWith';
|
||||||
@ -63,14 +63,14 @@ export class DataSourcePane extends PureComponent<DataSourcePaneProps, DataSourc
|
|||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.handleDataSourceListChange = this.handleDataSourceListChange.bind(this);
|
// this.handleDataSourceListChange = this.handleDataSourceListChange.bind(this);
|
||||||
this.handleImportDataSourceList = this.handleImportDataSourceList.bind(this);
|
// this.handleImportDataSourceList = this.handleImportDataSourceList.bind(this);
|
||||||
this.handleCreateDataSource = this.handleCreateDataSource.bind(this);
|
// this.handleCreateDataSource = this.handleCreateDataSource.bind(this);
|
||||||
this.handleUpdateDataSource = this.handleUpdateDataSource.bind(this);
|
// this.handleUpdateDataSource = this.handleUpdateDataSource.bind(this);
|
||||||
this.handleRemoveDataSource = this.handleRemoveDataSource.bind(this);
|
// this.handleRemoveDataSource = this.handleRemoveDataSource.bind(this);
|
||||||
this.handleDuplicateDataSource = this.handleDuplicateDataSource.bind(this);
|
// this.handleDuplicateDataSource = this.handleDuplicateDataSource.bind(this);
|
||||||
this.handleEditDataSource = this.handleEditDataSource.bind(this);
|
// this.handleEditDataSource = this.handleEditDataSource.bind(this);
|
||||||
this.handleTabChange = this.handleTabChange.bind(this);
|
// this.handleTabChange = this.handleTabChange.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDataSourceListChange = (dataSourceList?: DataSourceConfig[]) => {
|
handleDataSourceListChange = (dataSourceList?: DataSourceConfig[]) => {
|
||||||
@ -83,31 +83,66 @@ export class DataSourcePane extends PureComponent<DataSourcePaneProps, DataSourc
|
|||||||
};
|
};
|
||||||
|
|
||||||
handleImportDataSourceList = (toImport: DataSourceConfig[]) => {
|
handleImportDataSourceList = (toImport: DataSourceConfig[]) => {
|
||||||
this.closeTab(TAB_ITEM_IMPORT);
|
const importDataSourceList = () => {
|
||||||
this.setState(
|
this.closeTab(TAB_ITEM_IMPORT);
|
||||||
({ dataSourceList }) => ({
|
this.setState(
|
||||||
dataSourceList: dataSourceList.concat(toImport),
|
({ dataSourceList }) => ({
|
||||||
}),
|
dataSourceList: dataSourceList.concat(toImport),
|
||||||
() => {
|
}),
|
||||||
this.handleDataSourceListChange();
|
() => {
|
||||||
},
|
this.handleDataSourceListChange();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
if (!_isArray(toImport) || toImport.length === 0) {
|
||||||
|
Message.error('没有找到可导入的数据源');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const repeatedDataSourceList = toImport.filter(
|
||||||
|
item => !!this.state.dataSourceList.find(
|
||||||
|
dataSource => dataSource.id === item.id
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
if (repeatedDataSourceList.length > 0) {
|
||||||
|
Dialog.confirm({
|
||||||
|
content: `数据源(${repeatedDataSourceList.map(item => item.id).join(',')})已存在,如果导入会替换原数据源,是否继续?`,
|
||||||
|
onOk: () => {
|
||||||
|
importDataSourceList();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
importDataSourceList();
|
||||||
};
|
};
|
||||||
|
|
||||||
handleCreateDataSource = (toCreate: DataSourceConfig) => {
|
handleCreateDataSource = (toCreate: DataSourceConfig) => {
|
||||||
this.closeTab(TAB_ITEM_CREATE);
|
const create = () => {
|
||||||
this.setState(
|
this.closeTab(TAB_ITEM_CREATE);
|
||||||
({ dataSourceList }) => ({
|
this.setState(
|
||||||
dataSourceList: dataSourceList.concat([
|
({ dataSourceList }) => ({
|
||||||
{
|
dataSourceList: dataSourceList.concat([
|
||||||
...toCreate,
|
{
|
||||||
},
|
...toCreate,
|
||||||
]),
|
},
|
||||||
}),
|
]),
|
||||||
() => {
|
}),
|
||||||
this.handleDataSourceListChange();
|
() => {
|
||||||
},
|
this.handleDataSourceListChange();
|
||||||
);
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
if (this.state.dataSourceList.find(
|
||||||
|
dataSource => dataSource.id === toCreate.id
|
||||||
|
)) {
|
||||||
|
Dialog.confirm({
|
||||||
|
content: `数据源(${toCreate.id})已存在,如果导入会替换原数据源,是否继续?`,
|
||||||
|
onOk: () => {
|
||||||
|
create();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
create();
|
||||||
};
|
};
|
||||||
|
|
||||||
handleUpdateDataSource = (toUpdate: DataSourceConfig) => {
|
handleUpdateDataSource = (toUpdate: DataSourceConfig) => {
|
||||||
@ -130,14 +165,22 @@ export class DataSourcePane extends PureComponent<DataSourcePaneProps, DataSourc
|
|||||||
};
|
};
|
||||||
|
|
||||||
handleRemoveDataSource = (dataSourceId: string) => {
|
handleRemoveDataSource = (dataSourceId: string) => {
|
||||||
this.setState(
|
const remove = () => {
|
||||||
({ dataSourceList }) => ({
|
this.setState(
|
||||||
dataSourceList: dataSourceList.filter((item) => item.id !== dataSourceId),
|
({ dataSourceList }) => ({
|
||||||
}),
|
dataSourceList: dataSourceList.filter((item) => item.id !== dataSourceId),
|
||||||
() => {
|
}),
|
||||||
this.handleDataSourceListChange();
|
() => {
|
||||||
},
|
this.handleDataSourceListChange();
|
||||||
);
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
Dialog.confirm({
|
||||||
|
content: `确定要删除吗?`,
|
||||||
|
onOk: () => {
|
||||||
|
remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
handleDuplicateDataSource = (dataSourceId: string) => {
|
handleDuplicateDataSource = (dataSourceId: string) => {
|
||||||
@ -233,7 +276,7 @@ export class DataSourcePane extends PureComponent<DataSourcePaneProps, DataSourc
|
|||||||
}));
|
}));
|
||||||
this.setState({ activeTabKey: TAB_ITEM_IMPORT });
|
this.setState({ activeTabKey: TAB_ITEM_IMPORT });
|
||||||
} else {
|
} else {
|
||||||
Message.notice('当前已有一个导入数据源的 TAB 被大家');
|
Message.notice('当前已有一个导入数据源的 TAB');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -256,21 +299,21 @@ export class DataSourcePane extends PureComponent<DataSourcePaneProps, DataSourc
|
|||||||
// @todo onSelect 不行?
|
// @todo onSelect 不行?
|
||||||
return [
|
return [
|
||||||
_isArray(dataSourceTypes) && dataSourceTypes.length > 1 ? (
|
_isArray(dataSourceTypes) && dataSourceTypes.length > 1 ? (
|
||||||
<MenuButton size="small" label="新建" onItemClick={this.openCreateDataSourceTab}>
|
<MenuButton label="新建" onItemClick={this.openCreateDataSourceTab}>
|
||||||
{dataSourceTypes.map((type) => (
|
{dataSourceTypes.map((type) => (
|
||||||
<MenuButtonItem key={type.type}>{type.type}</MenuButtonItem>
|
<MenuButtonItem key={type.type}>{type.type}</MenuButtonItem>
|
||||||
))}
|
))}
|
||||||
</MenuButton>
|
</MenuButton>
|
||||||
) : _isArray(dataSourceTypes) && dataSourceTypes.length > 1 ? (
|
) : _isArray(dataSourceTypes) && dataSourceTypes.length === 1 ? (
|
||||||
<Button onClick={this.openImportDataSourceTab.bind(this, dataSourceTypes[0])}>导入</Button>
|
<Button onClick={this.openCreateDataSourceTab.bind(this, dataSourceTypes[0].type)}>新建</Button>
|
||||||
) : null,
|
) : null,
|
||||||
_isArray(importPlugins) && importPlugins.length > 1 ? (
|
_isArray(importPlugins) && importPlugins.length > 1 ? (
|
||||||
<MenuButton size="small" label="导入" onItemClick={this.openImportDataSourceTab}>
|
<MenuButton label="导入" onItemClick={this.openImportDataSourceTab}>
|
||||||
{importPlugins.map((plugin) => (
|
{importPlugins.map((plugin) => (
|
||||||
<MenuButtonItem key={plugin.name}>{plugin.name}</MenuButtonItem>
|
<MenuButtonItem key={plugin.name}>{plugin.name}</MenuButtonItem>
|
||||||
))}
|
))}
|
||||||
</MenuButton>
|
</MenuButton>
|
||||||
) : _isArray(importPlugins) && importPlugins.length > 1 ? (
|
) : _isArray(importPlugins) && importPlugins.length === 1 ? (
|
||||||
<Button onClick={this.openImportDataSourceTab.bind(this, importPlugins[0].name)}>导入</Button>
|
<Button onClick={this.openImportDataSourceTab.bind(this, importPlugins[0].name)}>导入</Button>
|
||||||
) : null,
|
) : null,
|
||||||
];
|
];
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"extends": "../../tsconfig.json",
|
"extends": "../../tsconfig.json",
|
||||||
"lib": ["es6", "dom"],
|
"lib": ["esnext", "dom"],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "lib"
|
"outDir": "lib"
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user