diff --git a/packages/demo/public/schema.json b/packages/demo/public/schema.json index 49f07baba..131b55860 100644 --- a/packages/demo/public/schema.json +++ b/packages/demo/public/schema.json @@ -13,7 +13,72 @@ "list": [ { "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, "options": { "uri": "https://www.taobao.com", diff --git a/packages/plugin-datasource-pane/CHANGELOG.md b/packages/plugin-datasource-pane/CHANGELOG.md new file mode 100644 index 000000000..e69de29bb diff --git a/packages/plugin-datasource-pane/README.md b/packages/plugin-datasource-pane/README.md index ea5630f97..4e0213a43 100644 --- a/packages/plugin-datasource-pane/README.md +++ b/packages/plugin-datasource-pane/README.md @@ -1,26 +1,10 @@ -TODO ---- +## 低代码引擎 - 数据源面板插件 -* 多语言 -* [later]表达式和其他类型的切换 -* 现有场景代码的兼容 -* class publich method bind issue -* ICON -* 支持变量 - -## 数据源面板 - -数据源管理 - -* 新建 -* 编辑 -* 导入 -* 指定数据源类型 -* 定制数据源导入插件 +对页面的数据源进行管理(新建,编辑,导入)。 ## 数据源类型定义 -内置变量,http 和 mtop 类型,支持传入自定义类型。 +内置 fetch 和 mtop 类型,支持传入自定义类型。 ``` type DataSourceType = { @@ -29,9 +13,7 @@ type DataSourceType = { }; ``` -数据源类型需要在集团规范约束下扩展。 - -目前只允许在 options 下添加扩展字段。 +数据源类型需要在集团规范约束下扩展。目前只允许在 options 下添加扩展字段。 比如 mtop 类型,需要添加 options.v (版本)字段。 @@ -56,16 +38,8 @@ interface DataSourcePaneImportPluginComponentProps extends DataSourcePaneImportP } ``` -## 问题 - -* 变量,上下文放数据源里管理是否合适 -* mockUrl 和 mockData -* 设计器的设计语言无法统一 - ## 插件开发 - +[https://yuque.antfin-inc.com/ali-lowcode/docs/ip4awq](插件开发文档)。 -## node 版本 - -v14.4.0 +本地开发需要在 v14.4.0 的 node 环境下进行。 diff --git a/packages/plugin-datasource-pane/TODO.md b/packages/plugin-datasource-pane/TODO.md new file mode 100644 index 000000000..3fbe5ebc5 --- /dev/null +++ b/packages/plugin-datasource-pane/TODO.md @@ -0,0 +1,18 @@ +TODO +--- + +* 多语言 +* ICON +* 支持变量 +* 定制样式 +* 不使用 bind +* 表达式 setter 的联想 +* [later]表达式和其他类型的切换 +* 变量,上下文的提案 +* mock 的提案 + +## 问题 + +* 变量,上下文放数据源里管理是否合适 +* mockUrl 和 mockData +* 设计器的设计语言无法统一 diff --git a/packages/plugin-datasource-pane/build.json b/packages/plugin-datasource-pane/build.json index 49a393b6b..e765b2233 100644 --- a/packages/plugin-datasource-pane/build.json +++ b/packages/plugin-datasource-pane/build.json @@ -1,7 +1,6 @@ { "plugins": [ - [ - "build-plugin-component" - ] + "build-plugin-component", + "build-plugin-fusion" ] } diff --git a/packages/plugin-datasource-pane/src/datasource-form.tsx b/packages/plugin-datasource-pane/src/datasource-form.tsx index 7fc5e9ab6..b4c2170c3 100644 --- a/packages/plugin-datasource-pane/src/datasource-form.tsx +++ b/packages/plugin-datasource-pane/src/datasource-form.tsx @@ -1,5 +1,6 @@ // @todo schema default import React, { PureComponent, ReactElement, FC } from 'react'; +import { Button } from '@alifd/next'; import { SchemaForm, FormButtonGroup, Submit } from '@formily/next'; import { ArrayTable, Input, Switch, NumberPicker } from '@formily/next-components'; import _isPlainObject from 'lodash/isPlainObject'; @@ -164,8 +165,6 @@ export class DataSourceForm extends PureComponent +
- + 提交 +
diff --git a/packages/plugin-datasource-pane/src/form-components/param-value.scss b/packages/plugin-datasource-pane/src/form-components/param-value.scss new file mode 100644 index 000000000..97541db8a --- /dev/null +++ b/packages/plugin-datasource-pane/src/form-components/param-value.scss @@ -0,0 +1,7 @@ +.param-value { + display: flex; + flex-direction: row; + .param-value-type { + margin-right: 4px; + } +} diff --git a/packages/plugin-datasource-pane/src/form-components/param-value.tsx b/packages/plugin-datasource-pane/src/form-components/param-value.tsx index 2cb723b37..99d8dee4c 100644 --- a/packages/plugin-datasource-pane/src/form-components/param-value.tsx +++ b/packages/plugin-datasource-pane/src/form-components/param-value.tsx @@ -1,5 +1,5 @@ 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 _isPlainObject from 'lodash/isPlainObject'; import _isArray from 'lodash/isArray'; @@ -10,21 +10,37 @@ import _get from 'lodash/get'; import _tap from 'lodash/tap'; import { ExpressionSetter } from '@ali/lowcode-editor-setters'; +import './param-value.scss'; + const { Group: RadioGroup } = Radio; +type ParamValueType = 'string' | 'number' | 'boolean' | 'expression'; + export interface ParamValueProps { className: string; value: any; onChange?: () => void; + types: ParamValueType[]; } export interface ParamValueState { type: 'string' | 'number' | 'boolean' | ''; } +const TYPE_LABEL_MAP = { + string: '字符串', + number: '数字', + boolean: '布尔', + expression: '表达式', +}; + class ParamValueComp extends PureComponent { static isFieldComponent = true; + static defaultProps = { + types: ['string', 'boolean', 'number', 'expression'], + }; + state = { type: '', }; @@ -48,7 +64,7 @@ class ParamValueComp extends PureComponent { // @todo 需要再 bind 一次? handleChange = (value) => { this.props?.onChange(value); - } + }; componentDidUpdate(prevProps) { if (this.props.value !== prevProps.value) { @@ -78,19 +94,46 @@ class ParamValueComp extends PureComponent { }); }; + renderTypeSelect = () => { + const { type } = this.state; + const { types } = this.props; + + if (_isArray(types) && types.length > 2) { + return ( + } {type === 'boolean' && } {type === 'number' && } diff --git a/packages/plugin-datasource-pane/src/import-plugins/code.scss b/packages/plugin-datasource-pane/src/import-plugins/code.scss new file mode 100644 index 000000000..a420f7a90 --- /dev/null +++ b/packages/plugin-datasource-pane/src/import-plugins/code.scss @@ -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; + } +} diff --git a/packages/plugin-datasource-pane/src/import-plugins/code.tsx b/packages/plugin-datasource-pane/src/import-plugins/code.tsx index a8f1d10ff..4dacccdd6 100644 --- a/packages/plugin-datasource-pane/src/import-plugins/code.tsx +++ b/packages/plugin-datasource-pane/src/import-plugins/code.tsx @@ -14,6 +14,8 @@ import { DataSourceConfig } from '@ali/lowcode-types'; import Ajv from 'ajv'; import { DataSourcePaneImportPluginComponentProps } from '../types'; +import './code.scss'; + export interface DataSourceImportPluginCodeProps extends DataSourcePaneImportPluginComponentProps { defaultValue?: DataSourceConfig[]; } @@ -115,11 +117,11 @@ export class DataSourceImportPluginCode extends PureComponent< const { code, isCodeValid } = this.state; return ( -
+
- {!isCodeValid &&

格式有误

} -

+ {!isCodeValid &&

格式有误

} +

- +

); diff --git a/packages/plugin-datasource-pane/src/index.scss b/packages/plugin-datasource-pane/src/index.scss index 67d1208f6..81a8d5c7b 100644 --- a/packages/plugin-datasource-pane/src/index.scss +++ b/packages/plugin-datasource-pane/src/index.scss @@ -12,7 +12,86 @@ } .lowcode-plugin-datasource-pane-list { - .next-virtual-list-wrapper { - min-height: 400px; + margin: 8px; + .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 { + + } } } diff --git a/packages/plugin-datasource-pane/src/index.tsx b/packages/plugin-datasource-pane/src/index.tsx index ccde8d705..2f0a3650e 100644 --- a/packages/plugin-datasource-pane/src/index.tsx +++ b/packages/plugin-datasource-pane/src/index.tsx @@ -4,6 +4,8 @@ import { DataSourcePane } from './pane'; import { DataSourcePaneImportPlugin, DataSourceType } from './types'; import { DataSourceImportPluginCode } from './import-plugins'; +import './index.scss'; + export { DataSourceImportPluginCode }; const PLUGIN_NAME = 'dataSourcePane'; diff --git a/packages/plugin-datasource-pane/src/list.tsx b/packages/plugin-datasource-pane/src/list.tsx index 4f0ace919..e589ee0df 100644 --- a/packages/plugin-datasource-pane/src/list.tsx +++ b/packages/plugin-datasource-pane/src/list.tsx @@ -64,57 +64,77 @@ export default class DataSourceList extends PureComponent (keyword ? item.id.indexOf(keyword) !== -1 : true)) ?.map((item) => (
  • - - {item.type} - {item.isInit ? '自动' : '手动'} +
    +
    +
    {item.id} - - -
    - } - align="r" - alignEdge - triggerType="hover" - style={{ width: 300 }} - > - ((acc, cur) => { - // @todo 这里的 ts 处理得不好 - if (_isPlainObject(item.options[cur])) { - Object.keys(item?.options?.[cur] || {}).forEach((curInOption) => { - acc.push({ - label: `${cur}.${curInOption}`, - value: (item?.options?.[cur] as any)?.[curInOption], - }); - }); - } else if (!_isNil(item.options[cur])) { - // @todo 排除 null - acc.push({ - label: cur, - value: item.options[cur], - }); - } - return acc; - }, []), console.log)} - > - - ( -
    - - {_isBoolean(val) ? 'bool' : _isNumber(val) ? 'number' : _isPlainObject(val) ? 'obj' : 'string'} - - {val.toString()} -
    - )} - /> -
    - + 详情} + align="b" + alignEdge + triggerType="hover" + style={{ width: 300 }} + > + ((acc, cur) => { + // @todo 这里的 ts 处理得不好 + if (_isPlainObject(item.options[cur])) { + Object.keys(item?.options?.[cur] || {}).forEach((curInOption) => { + acc.push({ + label: `${cur}.${curInOption}`, + value: (item?.options?.[cur] as any)?.[curInOption], + }); + }); + } else if (!_isNil(item.options[cur])) { + // @todo 排除 null + acc.push({ + label: cur, + value: item.options[cur], + }); + } + return acc; + }, []), + console.log, + )} + > + + ( +
    + + {_isBoolean(val) + ? 'bool' + : _isNumber(val) + ? 'number' + : _isPlainObject(val) + ? 'obj' + : 'string'} + + {val.toString()} +
    + )} + /> +
    +
    + + + +
    +
    + {item.type} + {item.isInit ? '自动' : '手动'} +
    +
  • )) || [] ); @@ -136,7 +156,9 @@ export default class DataSourceList extends PureComponent - {this.deriveListDataSource()} +
    + {this.deriveListDataSource()} +
    ); } diff --git a/packages/plugin-datasource-pane/src/pane.tsx b/packages/plugin-datasource-pane/src/pane.tsx index de1b41725..7c71e8508 100644 --- a/packages/plugin-datasource-pane/src/pane.tsx +++ b/packages/plugin-datasource-pane/src/pane.tsx @@ -3,7 +3,7 @@ */ import React, { PureComponent } from 'react'; 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 _uniqueId from 'lodash/uniqueId'; import _startsWith from 'lodash/startsWith'; @@ -63,14 +63,14 @@ export class DataSourcePane extends PureComponent { @@ -83,31 +83,66 @@ export class DataSourcePane extends PureComponent { - this.closeTab(TAB_ITEM_IMPORT); - this.setState( - ({ dataSourceList }) => ({ - dataSourceList: dataSourceList.concat(toImport), - }), - () => { - this.handleDataSourceListChange(); - }, + const importDataSourceList = () => { + this.closeTab(TAB_ITEM_IMPORT); + this.setState( + ({ dataSourceList }) => ({ + dataSourceList: dataSourceList.concat(toImport), + }), + () => { + 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) => { - this.closeTab(TAB_ITEM_CREATE); - this.setState( - ({ dataSourceList }) => ({ - dataSourceList: dataSourceList.concat([ - { - ...toCreate, - }, - ]), - }), - () => { - this.handleDataSourceListChange(); - }, - ); + const create = () => { + this.closeTab(TAB_ITEM_CREATE); + this.setState( + ({ dataSourceList }) => ({ + dataSourceList: dataSourceList.concat([ + { + ...toCreate, + }, + ]), + }), + () => { + this.handleDataSourceListChange(); + }, + ); + }; + if (this.state.dataSourceList.find( + dataSource => dataSource.id === toCreate.id + )) { + Dialog.confirm({ + content: `数据源(${toCreate.id})已存在,如果导入会替换原数据源,是否继续?`, + onOk: () => { + create(); + } + }); + return; + } + create(); }; handleUpdateDataSource = (toUpdate: DataSourceConfig) => { @@ -130,14 +165,22 @@ export class DataSourcePane extends PureComponent { - this.setState( - ({ dataSourceList }) => ({ - dataSourceList: dataSourceList.filter((item) => item.id !== dataSourceId), - }), - () => { - this.handleDataSourceListChange(); - }, - ); + const remove = () => { + this.setState( + ({ dataSourceList }) => ({ + dataSourceList: dataSourceList.filter((item) => item.id !== dataSourceId), + }), + () => { + this.handleDataSourceListChange(); + }, + ); + }; + Dialog.confirm({ + content: `确定要删除吗?`, + onOk: () => { + remove(); + } + }); }; handleDuplicateDataSource = (dataSourceId: string) => { @@ -233,7 +276,7 @@ export class DataSourcePane extends PureComponent 1 ? ( - + {dataSourceTypes.map((type) => ( {type.type} ))} - ) : _isArray(dataSourceTypes) && dataSourceTypes.length > 1 ? ( - + ) : _isArray(dataSourceTypes) && dataSourceTypes.length === 1 ? ( + ) : null, _isArray(importPlugins) && importPlugins.length > 1 ? ( - + {importPlugins.map((plugin) => ( {plugin.name} ))} - ) : _isArray(importPlugins) && importPlugins.length > 1 ? ( + ) : _isArray(importPlugins) && importPlugins.length === 1 ? ( ) : null, ]; diff --git a/packages/plugin-datasource-pane/tsconfig.json b/packages/plugin-datasource-pane/tsconfig.json index 020e1e82f..df5f697e9 100644 --- a/packages/plugin-datasource-pane/tsconfig.json +++ b/packages/plugin-datasource-pane/tsconfig.json @@ -1,6 +1,6 @@ { "extends": "../../tsconfig.json", - "lib": ["es6", "dom"], + "lib": ["esnext", "dom"], "compilerOptions": { "outDir": "lib" },