diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 47a1592534b..a39257803a5 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -30,4 +30,5 @@ - [](./API/FormCard.md) - [](./API/FormBlock.md) - [](./API/FormItemGrid.md) - - [](./API/FormSlot.md) \ No newline at end of file + - [](./API/FormSlot.md) +- [PlayGround](../packages/builder-next/lib/index.js) \ No newline at end of file diff --git a/packages/builder-next/.npmignore b/packages/builder-next/.npmignore new file mode 100644 index 00000000000..b423fb999cb --- /dev/null +++ b/packages/builder-next/.npmignore @@ -0,0 +1,3 @@ +node_modules +*.log +build diff --git a/packages/builder-next/LICENSE.md b/packages/builder-next/LICENSE.md new file mode 100644 index 00000000000..2bd9316cd51 --- /dev/null +++ b/packages/builder-next/LICENSE.md @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2015-present, Alibaba Group Holding Limited. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/packages/builder-next/README.md b/packages/builder-next/README.md new file mode 100644 index 00000000000..9d2412db39e --- /dev/null +++ b/packages/builder-next/README.md @@ -0,0 +1,2 @@ +# @uform/builder-next +> UForm 可视化配置 next实现 \ No newline at end of file diff --git a/packages/builder-next/package.json b/packages/builder-next/package.json new file mode 100644 index 00000000000..43e769750fd --- /dev/null +++ b/packages/builder-next/package.json @@ -0,0 +1,29 @@ +{ + "name": "@uform/builder-next", + "version": "0.1.0-beta.15", + "license": "MIT", + "main": "lib/index.js", + "repository": { + "type": "git", + "url": "git+https://github.com/alibaba/uform.git" + }, + "bugs": { + "url": "https://github.com/alibaba/uform/issues" + }, + "homepage": "https://github.com/alibaba/uform#readme", + "engines": { + "npm": ">=3.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + }, + "dependencies": { + "@alifd/next": "^1.13.1", + "@uform/builder": "^0.1.0-beta.14" + }, + "publishConfig": { + "access": "public" + }, + "gitHead": "f513fc2dcca781b3f7aa588c4419bce20cba2d8b" +} \ No newline at end of file diff --git a/packages/builder-next/src/index.js b/packages/builder-next/src/index.js new file mode 100644 index 00000000000..2a8e83f8e9a --- /dev/null +++ b/packages/builder-next/src/index.js @@ -0,0 +1,142 @@ +import React from 'react' +import SchemaForm, { FormButtonGroup, Submit, Reset } from '@uform/next' +import Builder from '@uform/builder' + +import { + Button, + Collapse, + Message, + Upload, + Input, + Select, + DatePicker, + Icon, + Checkbox, + NumberPicker, + TimePicker, + Radio, + Form, + Tab +} from '@alifd/next' + +// style +import '@alifd/next/dist/next.css' + +SchemaForm.FormButtonGroup = FormButtonGroup +SchemaForm.Submit = Submit +SchemaForm.Reset = Reset + +const renderSchema = {} + +const props = { + UI: { + version: '1.x', + Button, + Accordion: Collapse, + Toast: Message, + Upload, + Input, + Select, + Icon, + DatePicker, + TimePicker, + Checkbox, + NumberPicker, + Radio, + RadioGroup: Radio.Group, + TabPane: Tab.Item, + Form, + Tab + }, + // 主题: dark/light,默认dark + themeStyle: 'dark', + // 是否展示布局组件,默认为false + showLayoutField: true, + // 是否展示预览按钮,默认为true + showPreviewBtn: true, + // 是否展示源码按钮 + showSourceCodeBtn: true, + // 控制返回按钮点击事件 + onBackBtnClick: () => { + alert('点击了返回') + }, + // 额外全局按钮 + globalButtonList: [ + // { + // key: 'submit', + // title: '自定义保存', + // render: (props) => { + // return {props.children} + // }, + // props: { + // // loading: true, + // }, + // }, { + // key: 'cancel', + // title: '取消', + // props: { + // onClick: () => { + // alert('点击取消'); + // } + // }, + // } + ], + // 是否展示全局配置 + showGlobalCfg: true, + // 全局配置额外项 + extraGlobalCfgList: [ + { + name: 'labelCol', + title: 'label宽度占比', + type: 'string' + }, + { + name: 'wrapperCol', + title: 'wrapper宽度占比', + type: 'string' + } + ], + globalCfg: {}, + supportFieldList: [], + includeFieldListKeyList: [ + 'input', + 'multipleInput', + 'number', + 'radio', + 'checkbox', + 'date', + 'month', + 'daterange', + 'time' + ], + + // 渲染引擎 + renderEngine: SchemaForm, + + schema: renderSchema, + // onChange: (data) => { + // console.info('index onChange data', data); + // }, + onSubmit: data => { + console.info('index onSubmit data', data) + } +} + +class Component extends React.Component { + constructor(props) { + super(props) + this.state = { + schema: renderSchema + } + } + + render() { + return ( +
+ +
+ ) + } +} + +export default Component diff --git a/packages/builder/package.json b/packages/builder/package.json index acbe8fc9869..c21e43e8d65 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -43,7 +43,8 @@ "redux-logger": "^3.0.6", "redux-thunk": "^2.2.0", "styled-components": "^4.1.2", - "uuid": "^3.2.1" + "uuid": "^3.2.1", + "react-dnd": "^7.4.1" }, "publishConfig": { "access": "public" diff --git a/packages/builder/src/App.js b/packages/builder/src/App.js index 0546111588f..e9ec1332d28 100644 --- a/packages/builder/src/App.js +++ b/packages/builder/src/App.js @@ -1,7 +1,6 @@ import React, { Component } from 'react' import cls from 'classnames' import PropTypes from 'prop-types' -import { SchemaForm } from './utils/baseForm' import { connect } from 'react-redux' import { changePreview, @@ -19,17 +18,85 @@ import AppStyle from './style' // components import FieldList from './components/fields/index' import Preview from './components/preview/index' -import AccordionList from './components/props/accordList' import generateGlobalBtnList from './components/globalBtnList/index' +import PropsSetting from './components/props/propsSetting' +import { SchemaForm, Field } from './utils/baseForm' +import defaultGlobalCfgList from './configs/supportGlobalCfgList' + const noop = () => {} class App extends Component { constructor(props) { super(props) this.state = { - systemError: false + systemError: false, + accordionList: [] + } + } + + generateGlobalCfgList = () => { + // Merge custom form global property configuration + const globalCfgList = [ + ...defaultGlobalCfgList, + ...this.props.extraGlobalCfgList + ] + const _globalCfgList = [] + for (let i = globalCfgList.length - 1; i >= 0; i--) { + if ( + !_globalCfgList.find(cfgItem => cfgItem.name === globalCfgList[i].name) + ) { + _globalCfgList.unshift(globalCfgList[i]) + } + } + return _globalCfgList + } + + // global config + renderGlobalConfig = () => { + const globalCfgList = this.generateGlobalCfgList() + + const content = ( + { + this.props.changeGbConfig(value) + }} + defaultValue={this.props.gbConfig} + labelAlign='left' + labelTextAlign='right' + > + {globalCfgList.map(props => ( + + ))} + + ) + + return content + } + + getAccordionList = () => { + const list = [ + { + title: '组件配置', + content: ( + + ), + expanded: true + } + ] + + if (this.props.showGlobalCfg) { + list.unshift({ + title: '全局配置', + content: this.renderGlobalConfig(), + expanded: true + }) } + return list } componentWillMount() { @@ -44,6 +111,12 @@ class App extends Component { _initSchema(schema) } + componentDidMount() { + this.setState({ + accordionList: this.getAccordionList() + }) + } + componentWillUnmount() { // Clear the selected componentId with the selected component this.props.changeComponent() @@ -138,6 +211,7 @@ class App extends Component { render() { const { initSchemaData, renderEngine } = this.props + const { Accordion, version: UIVersion } = this.props.UI const contentHeight = window.innerHeight - 64 @@ -169,10 +243,28 @@ class App extends Component { />
- +
- + {UIVersion === '1.x' ? ( + + ) : ( + { + this.setState({ + accordionList: list + }) + }} + /> + )}
{this.getEditorTpl()} diff --git a/packages/builder/src/__tests__/reducers/index.spec.js b/packages/builder/src/__tests__/reducers/index.spec.js index d180b8fccfa..1820e75ae50 100644 --- a/packages/builder/src/__tests__/reducers/index.spec.js +++ b/packages/builder/src/__tests__/reducers/index.spec.js @@ -66,9 +66,8 @@ describe('reducers', () => { name: '__id__', title: '唯一标识', type: 'string', - description: '发起请求时带过去的参数字段', - required: true, - value: '11111' + description: '唯一标识:发起请求时带上的参数id,必填,全局保证唯一。', + required: true }, { name: 'description', title: '提示文案', type: 'string' }, { @@ -215,11 +214,14 @@ describe('reducers', () => { test('gbConfig reducers return initial state', () => { expect(gbConfigReducer(undefined, {})).toEqual({ labelAlign: 'left', - labelTextAlign: 'left', + labelTextAlign: 'right', autoAddColon: true, needFormButtonGroup: false, inline: false, - size: 'medium' + size: 'medium', + labelCol: 8, + wrapperCol: 16, + editable: true }) }) test('gbConfig reducers return custom state', () => { @@ -229,7 +231,9 @@ describe('reducers', () => { autoAddColon: true, needFormButtonGroup: false, inline: false, - size: 'small' + size: 'small', + labelCol: 8, + wrapperCol: 16 } const action = { @@ -248,7 +252,10 @@ describe('reducers', () => { needFormButtonGroup: false, inline: true, size: 'large', - extra: 'extra' + extra: 'extra', + labelCol: 8, + wrapperCol: 16, + editable: true } expect(gbConfigReducer(beforeState, action)).toEqual(afterState) @@ -480,8 +487,7 @@ describe('reducers', () => { title: '单行文本框', placeholder: '请输入', 'x-index': 0, - id: '111', - __id__: '111' + id: '111' } } } @@ -491,7 +497,7 @@ describe('reducers', () => { '111': { type: 'object', id: '111', - __id__: '111', + 'x-index': 0, 'x-component': 'layout', properties: {}, 'x-props': { @@ -533,8 +539,7 @@ describe('reducers', () => { title: '单行文本框', placeholder: '请输入', 'x-index': 0, - id: '222', - __id__: '222' + id: '222' } } } @@ -547,8 +552,7 @@ describe('reducers', () => { type: 'string', title: '111', 'x-index': 0, - id: '111', - __id__: '111' + id: '111' }, '222': { key: 'input', @@ -560,15 +564,13 @@ describe('reducers', () => { title: '单行文本框', placeholder: '请输入', 'x-index': 1, - id: '222', - __id__: '222' + id: '222' }, '333': { type: 'string', title: '333', 'x-index': 2, - id: '333', - __id__: '333' + id: '333' } } } diff --git a/packages/builder/src/actions/index.js b/packages/builder/src/actions/index.js index d46c5dc5688..a2f4640bf88 100644 --- a/packages/builder/src/actions/index.js +++ b/packages/builder/src/actions/index.js @@ -28,7 +28,11 @@ export const addComponentAndEdit = ( dispatch(addComponent(component, existId, id, type, containerId)) dispatch(changeComponent(id)) dispatch(showComponentProps(id, component, containerId)) - dispatch(changeLayoutId(containerId)) + + if (component.__key__ === 'layout') { + dispatch(changeLayoutId(id)) + } + dispatch( editComponent( id, diff --git a/packages/builder/src/components/fields/index.js b/packages/builder/src/components/fields/index.js index 73a2bf5e427..75cba201334 100644 --- a/packages/builder/src/components/fields/index.js +++ b/packages/builder/src/components/fields/index.js @@ -63,7 +63,8 @@ class FieldList extends Component { : fieldItem renderFieldList() { - const _addComponent = this.props.addComponentAndEdit + const _addComponentAndEdit = this.props.addComponentAndEdit + return (
    {this.fieldList.map((fieldItem, i) => { @@ -80,7 +81,7 @@ class FieldList extends Component { draggable onDragStart={ev => this.onDragStart(ev, newFieldItem)} onClick={() => { - _addComponent && _addComponent(newFieldItem) + _addComponentAndEdit && _addComponentAndEdit(newFieldItem) }} > ({}) +const mapStateToProps = state => state const mapDispatchToProps = dispatch => ({ addComponent: component => dispatch(addComponent(component)), @@ -122,7 +123,8 @@ const mapDispatchToProps = dispatch => ({ dispatch(editComponent(id, propsData, containerId)), showComponentProps: (id, comp) => dispatch(showComponentProps(id, comp)), changeComponent: componentId => dispatch(changeComponent(componentId)), - addComponentAndEdit: component => dispatch(addComponentAndEdit(component)) + addComponentAndEdit: (component, existId, type, containerId) => + dispatch(addComponentAndEdit(component, existId, type, containerId)) }) class StyledFieldListComp extends React.Component { diff --git a/packages/builder/src/components/fields/layout.js b/packages/builder/src/components/fields/layout.js index 88e31ff7ad0..65f4f816247 100644 --- a/packages/builder/src/components/fields/layout.js +++ b/packages/builder/src/components/fields/layout.js @@ -33,7 +33,10 @@ class Component extends React.Component { // eslint-disable-next-line key={i} onClick={() => { - _addComponentAndEdit && _addComponentAndEdit(item) + _addComponentAndEdit && + _addComponentAndEdit( + item + ) }} > {title} @@ -57,10 +60,11 @@ class Component extends React.Component { } } -const mapStateToProps = () => ({}) +const mapStateToProps = state => state const mapDispatchToProps = dispatch => ({ - addComponentAndEdit: component => dispatch(addComponentAndEdit(component)) + addComponentAndEdit: (component, existId, type, containerId) => + dispatch(addComponentAndEdit(component, existId, type, containerId)) }) class StyledLayoutListComp extends React.Component { diff --git a/packages/builder/src/components/preview/fieldMiddleware.js b/packages/builder/src/components/preview/fieldMiddleware.js index 516ba53bf7c..07864b8bf43 100644 --- a/packages/builder/src/components/preview/fieldMiddleware.js +++ b/packages/builder/src/components/preview/fieldMiddleware.js @@ -7,11 +7,14 @@ export default (FormConsumer, that) => { if (hasRegisted) { return false } + const { UI } = that.props window.__hasRegisted__ = true registerFieldMiddleware(Field => props => React.createElement(FormConsumer, {}, (obj = {}) => { const { type } = obj - if (props.path.length === 0 || type !== 'preview') { return React.createElement(Field, props) } + if (props.path.length === 0 || type !== 'preview') { + return React.createElement(Field, props) + } const { title = '', active = false } = props.schema const id = props.path[0] const comp = { @@ -49,15 +52,7 @@ export default (FormConsumer, that) => { className='preview-line-layer-layout' title='编辑' > - { - React.createElement(Field, { - 'x-component': 'Icon', - 'x-props': { - type: 'edit', - size: 'small' - } - }) - } + { }} title='删除' > - { - React.createElement(Field, { - 'x-component': 'Icon', - 'x-props': { - type: 'ashbin', - size: 'small' - } - }) - } + diff --git a/packages/builder/src/components/preview/index.js b/packages/builder/src/components/preview/index.js index abe5f93f822..ea363f36704 100644 --- a/packages/builder/src/components/preview/index.js +++ b/packages/builder/src/components/preview/index.js @@ -143,11 +143,15 @@ class Preview extends Component { ) const globalCfg = pick(gbConfig, [ + 'labelCol', + 'wrapperCol', + 'action', 'labelAlign', 'labelTextAlign', 'autoAddColon', 'inline', - 'size' + 'size', + 'editable' ]) return ( diff --git a/packages/builder/src/components/props/accordList.js b/packages/builder/src/components/props/accordList.js deleted file mode 100644 index c27fdd7d70a..00000000000 --- a/packages/builder/src/components/props/accordList.js +++ /dev/null @@ -1,103 +0,0 @@ -import React from 'react' -import PropsSetting from './propsSetting' -import { SchemaForm, Field } from '../../utils/baseForm' -import defaultGlobalCfgList from '../../configs/supportGlobalCfgList' - -export default class extends React.Component { - constructor(props) { - super(props) - this.state = { - accordionList: this.getAccordionList() - } - } - - componentDidMount() { - // this.setState({ - // accordionList: this.getAccordionList() - // }) - } - - generateGlobalCfgList = () => { - // Merge custom form global property configuration - const globalCfgList = [ - ...defaultGlobalCfgList, - ...this.props.extraGlobalCfgList - ] - const _globalCfgList = [] - for (let i = globalCfgList.length - 1; i >= 0; i--) { - if ( - !_globalCfgList.find(cfgItem => cfgItem.name === globalCfgList[i].name) - ) { - _globalCfgList.unshift(globalCfgList[i]) - } - } - return _globalCfgList - } - - // global config - renderGlobalConfig = () => { - const globalCfgList = this.generateGlobalCfgList() - - const content = ( - { - this.props.changeGbConfig(value) - }} - defaultValue={this.props.gbConfig} - labelAlign='left' - labelTextAlign='left' - > - {globalCfgList.map(props => ( - - ))} - - ) - - return content - } - - getAccordionList() { - const list = [ - { - title: '组件配置', - content: ( - - ), - expanded: true - } - ] - - if (this.props.showGlobalCfg) { - list.unshift({ - title: '全局配置', - content: this.renderGlobalConfig(), - expanded: true - }) - } - return list - } - - render() { - const { Accordion, version: UIVersion } = this.props.UI - - return UIVersion === '1.x' ? ( - - ) : ( - { - this.setState({ - accordionList: list - }) - }} - /> - ) - } -} diff --git a/packages/builder/src/components/props/colsDetail.js b/packages/builder/src/components/props/colsDetail.js new file mode 100644 index 00000000000..c969bd83f0d --- /dev/null +++ b/packages/builder/src/components/props/colsDetail.js @@ -0,0 +1,53 @@ +import React from 'react' +import PropTypes from 'prop-types' + +class ColsDetail extends React.Component { + static propTypes = { + value: PropTypes.arrayOf(PropTypes.any), + onChange: PropTypes.func + } + + handleChange = (idx, val) => { + const { UI } = this.props + if (!val) { + UI.Toast.error('请确保列宽是有效整数') + return false + } + const { onChange, value } = this.props + let newValue = [...value] + const diff = val - newValue[idx] + + if (diff >= newValue[newValue.length - 1]) { + UI.Toast.error('请确保4列宽度加起来等于24') + return false + } + + newValue = newValue.map((_val, i) => { + if (i === idx) { + return val + } + if (i === newValue.length - 1) { + return _val - diff + } + if (i < idx) { + return _val + } + return _val + }) + + onChange(newValue) + } + + render() { + const { value = [], UI } = this.props + return value.map((item, idx) => ( + this.handleChange(idx, val)} + /> + )) + } +} + +export default ColsDetail diff --git a/packages/builder/src/components/props/editors/fieldAttrEditors/defaultValueEditor/dateDefaultEditor.js b/packages/builder/src/components/props/editors/fieldAttrEditors/defaultValueEditor/dateDefaultEditor.js index 1f8eada249c..46376d97ebc 100644 --- a/packages/builder/src/components/props/editors/fieldAttrEditors/defaultValueEditor/dateDefaultEditor.js +++ b/packages/builder/src/components/props/editors/fieldAttrEditors/defaultValueEditor/dateDefaultEditor.js @@ -69,7 +69,7 @@ class Editor extends Component { }} /> ), - specify: + specify: }} /> ) diff --git a/packages/builder/src/components/props/editors/fieldAttrEditors/defaultValueEditor/dateTimeDefaultEditor.js b/packages/builder/src/components/props/editors/fieldAttrEditors/defaultValueEditor/dateTimeDefaultEditor.js index c071f92ba66..a818e1c69d4 100644 --- a/packages/builder/src/components/props/editors/fieldAttrEditors/defaultValueEditor/dateTimeDefaultEditor.js +++ b/packages/builder/src/components/props/editors/fieldAttrEditors/defaultValueEditor/dateTimeDefaultEditor.js @@ -17,20 +17,24 @@ const ds = [ ] const DatePickerDefault = props => ( - { - props.onChange(vStr) + if (vStr) { + props.onChange(vStr) + } else { + props.onChange(v.format('HH:mm:ss')) + } }} style={{ verticalAlign: 'top', - marginLeft: 20 + marginLeft: 5 }} /> ) class Editor extends Component { render() { + const { UI } = this.props return ( , - specify: + specify: }} /> ) diff --git a/packages/builder/src/components/props/propsSetting.js b/packages/builder/src/components/props/propsSetting.js index 947c55f9ffc..7eb414e492f 100644 --- a/packages/builder/src/components/props/propsSetting.js +++ b/packages/builder/src/components/props/propsSetting.js @@ -1,6 +1,10 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' -import { SchemaForm } from '../../utils/baseForm' +import { + SchemaForm, + registerFormFields, + connect as formConnect +} from '../../utils/baseForm' import { connect } from 'react-redux' import { showComponentProps, @@ -16,6 +20,7 @@ import FileSetting from './fileSetting' import './defaultValueCascader/index' import './dataSourceEditor/index' +import ColsDetail from './colsDetail' import pickBy from 'lodash.pickby' @@ -28,6 +33,17 @@ class PropsSetting extends Component { componentProps: PropTypes.object } + constructor(props) { + super(props) + registerFormFields({ + colsDetail: formConnect({ + defaultProps: { + UI: this.props.UI + } + })(ColsDetail) + }) + } + onChangeHandler = formdata => { const { componentId = '' } = this.props if (!componentId) return false @@ -156,7 +172,9 @@ class PropsSetting extends Component { renderConfigList() { const { componentId = '' } = this.props - if (!componentId) { return

    请选择待编辑的表单字段

    } + if (!componentId) { + return

    请选择待编辑的表单字段

    + } return ( @@ -190,7 +208,7 @@ class PropsSetting extends Component { onChange={this.onChangeHandler} schema={this.generatePropsSchema()} labelAlign='left' - labelTextAlign='left' + labelTextAlign='right' labelCol={8} > {' '} diff --git a/packages/builder/src/configs/supportConfigList.js b/packages/builder/src/configs/supportConfigList.js index c9befdd2dc6..dd1644b7140 100644 --- a/packages/builder/src/configs/supportConfigList.js +++ b/packages/builder/src/configs/supportConfigList.js @@ -4,7 +4,7 @@ const FIELDLIST = { name: '__id__', title: '唯一标识', type: 'string', - description: '发起请求时带过去的参数字段', + description: '唯一标识:发起请求时带上的参数id,必填,全局保证唯一。', required: true }, PLACEHOLDER: { @@ -133,6 +133,9 @@ export const getPropsByKey = key => { 'PLACEHOLDER' ]) case 'date': + case 'month': + case 'daterange': + case 'time': return generateProps( [ 'ID', @@ -215,6 +218,27 @@ export const getPropsByKey = key => { } ] ) + case 'wrapper_card': + return generateProps( + ['ID'], + [ + { + name: 'x-props.title', + title: '标题', + type: 'string' + }, + { + name: 'x-props.subTitle', + title: '副标题', + type: 'string' + }, + { + name: 'x-props.showHeadDivider', + title: '是否展示标题底部横线', + type: 'boolean' + } + ] + ) default: return defaultProps } diff --git a/packages/builder/src/configs/supportGlobalCfgList.js b/packages/builder/src/configs/supportGlobalCfgList.js index 59c8ed3feb2..10fbdd98475 100644 --- a/packages/builder/src/configs/supportGlobalCfgList.js +++ b/packages/builder/src/configs/supportGlobalCfgList.js @@ -23,11 +23,14 @@ const sizeEnum = [ // 默认全局配置值 export const defaultGlobalCfgValue = { labelAlign: 'left', - labelTextAlign: 'left', + labelTextAlign: 'right', autoAddColon: true, needFormButtonGroup: false, inline: false, - size: 'medium' + size: 'medium', + labelCol: 8, + wrapperCol: 16, + editable: true } // 默认全局配置属性列表 diff --git a/packages/builder/src/configs/supportLayoutList.js b/packages/builder/src/configs/supportLayoutList.js index ca0972a8022..7059efeb77f 100644 --- a/packages/builder/src/configs/supportLayoutList.js +++ b/packages/builder/src/configs/supportLayoutList.js @@ -25,5 +25,19 @@ export default [ gutter: 20 } } + }, + { + key: 'wrapper_card', + icon: 'clock-circle-o', + type: 'object', + title: 'FormCard卡片式布局', + __key__: 'layout', + __key__data__: { + 'x-component': 'card', + 'x-props': { + title: '卡片式布局', + showHeadDivider: true + } + } } ] diff --git a/packages/builder/src/demo/index-1-x.js b/packages/builder/src/demo/index-1-x.js index efb169f5004..56b53af8b1d 100644 --- a/packages/builder/src/demo/index-1-x.js +++ b/packages/builder/src/demo/index-1-x.js @@ -1,5 +1,5 @@ import React from 'react' -import SchemaForm from '@uform/next' +import SchemaForm, { FormButtonGroup, Submit, Reset } from '@uform/next' import Index from '../index' import { Button, @@ -12,6 +12,7 @@ import { Icon, Checkbox, NumberPicker, + TimePicker, Radio, Form, Tab @@ -20,6 +21,10 @@ import { // style import '@alifd/next/dist/next.css' +SchemaForm.FormButtonGroup = FormButtonGroup +SchemaForm.Submit = Submit +SchemaForm.Reset = Reset + const renderSchema = {} const props = { @@ -33,6 +38,7 @@ const props = { Select, Icon, DatePicker, + TimePicker, Checkbox, NumberPicker, Radio, @@ -44,7 +50,7 @@ const props = { // 主题: dark/light,默认dark // themeStyle: 'light', // 是否展示布局组件,默认为false - showLayoutField: false, + showLayoutField: true, showPreviewBtn: true, showSourceCodeBtn: true, // 控制返回按钮点击事件 @@ -75,10 +81,37 @@ const props = { // 是否展示全局配置 showGlobalCfg: true, // 全局配置额外项 - extraGlobalCfgList: [], + extraGlobalCfgList: [ + { + name: 'labelCol', + title: 'label宽度占比', + type: 'string' + }, + { + name: 'wrapperCol', + title: 'wrapper宽度占比', + type: 'string' + }, + { + name: 'editable', + title: '表单是否可编辑', + description: '若设置为false,则可快速搭建出表单详情页,只需设置每个组件的默认值', + type: 'boolean' + } + ], globalCfg: {}, supportFieldList: [], - includeFieldListKeyList: ['input', 'multipleInput', 'number', 'radio', 'checkbox', 'date', 'month', 'daterange', 'time'], + includeFieldListKeyList: [ + 'input', + 'multipleInput', + 'number', + 'radio', + 'checkbox', + 'date', + 'month', + 'daterange', + 'time' + ], // 渲染引擎 renderEngine: SchemaForm, diff --git a/packages/builder/src/demo/index.js b/packages/builder/src/demo/index.js index fd40670ddef..4e922b43647 100644 --- a/packages/builder/src/demo/index.js +++ b/packages/builder/src/demo/index.js @@ -4,7 +4,7 @@ import Index from '../index' import { Button, Accordion, - Message, + Feedback, Upload, Input, Select, @@ -17,8 +17,6 @@ import { Tab } from '@alife/next' -// style -// import '@alifd/next/dist/next.css' import '@alife/next/dist/next.min.css' const renderSchema = {} @@ -28,7 +26,7 @@ const props = { version: '0.x', Button, Accordion, - Toast: Message, + Toast: Feedback.toast, Upload, Input, Select, diff --git a/packages/builder/src/index.js b/packages/builder/src/index.js index 79291168d4a..c6f589dee19 100644 --- a/packages/builder/src/index.js +++ b/packages/builder/src/index.js @@ -26,8 +26,11 @@ const initialState = { codemode: false, componentProps: {}, gbConfig: { + action: '', + labelCol: 8, + wrapperCol: 8, labelAlign: 'left', - labelTextAlign: 'left', + labelTextAlign: 'right', autoAddColon: true, needFormButtonGroup: false, inline: false, diff --git a/packages/builder/src/reducers/componentProps.js b/packages/builder/src/reducers/componentProps.js index 460ddcf8946..8bcb1f360f9 100644 --- a/packages/builder/src/reducers/componentProps.js +++ b/packages/builder/src/reducers/componentProps.js @@ -13,11 +13,6 @@ export default (state = {}, action) => { return Object.assign( {}, item, - name === '__id__' - ? { - value: id - } - : {}, comp[name] ? { value: comp[name] diff --git a/packages/builder/src/reducers/initSchemaData.js b/packages/builder/src/reducers/initSchemaData.js index 6f9b83324bf..17b75c8f10a 100644 --- a/packages/builder/src/reducers/initSchemaData.js +++ b/packages/builder/src/reducers/initSchemaData.js @@ -75,21 +75,21 @@ export default (state = {}, action) => { } return newState case 'ADD_COMPONENT': - if (component.__key__ === 'layout') { - // 判断是否布局组件特殊处理 - newState.properties[id] = { - type: 'object', - id, - __id__: id, - ...component.__key__data__, - properties: {}, - 'x-props': { - ...component.__key__data__['x-props'], - _extra: component + const _component_ = + component.__key__ === 'layout' + ? { + type: 'object', + id, + ...component.__key__data__, + properties: {}, + 'x-props': { + ...component.__key__data__['x-props'], + _extra: component + } + } + : { + ...component } - } - return newState - } const propertiesList1 = addType === 'layout' @@ -108,14 +108,14 @@ export default (state = {}, action) => { } } propertiesList1[idx] = { - ...component, + ..._component_, id, 'x-index': idx } } else { // 在最后插入新的组件 propertiesList1[propertiesList1.length] = { - ...component, + ..._component_, id, 'x-index': propertiesList1.length } @@ -124,8 +124,7 @@ export default (state = {}, action) => { const _properties1 = {} propertiesList1.forEach(item => { _properties1[item.id] = { - ...item, - __id__: item.id + ...item } }) diff --git a/packages/builder/src/style.js b/packages/builder/src/style.js index 6ccb1fbde2b..2a9c4ebdb3f 100644 --- a/packages/builder/src/style.js +++ b/packages/builder/src/style.js @@ -10,6 +10,9 @@ export default styled.div` .next-checkbox-label { color: ${props => props.theme.whiteColor}; } + .preview-main .next-checkbox-label { + color: #333; + } .schemaform-header { position: relative; height: 64px; @@ -38,7 +41,8 @@ export default styled.div` top: 24px; width: 9px; height: 17px; - background: url('${props => props.theme.backIconUrl}') no-repeat center center; + background: url('${props => + props.theme.backIconUrl}') no-repeat center center; background-size: 9px 17px; } &::after { diff --git a/packages/builder/src/utils/lang.js b/packages/builder/src/utils/lang.js index c508906bb89..1265165a7b4 100644 --- a/packages/builder/src/utils/lang.js +++ b/packages/builder/src/utils/lang.js @@ -18,7 +18,7 @@ export const isNum = isType('Number') export const isIter = obj => isArr(obj) || isObj(obj) const replaceSingleDefault = v => { - if (!isFlagValue(v)) return v + if (!isFlagValue(v)) return '' const { type, flag, value } = v @@ -41,7 +41,7 @@ const replaceSingleDefault = v => { if (type === 'specify') { return value } else if (type === 'now') { - return now.format('YYYY-MM-DD HH:MM:SS') + return now.format('HH:MM:SS') } else if (type === 'url') { return params[value] } diff --git a/packages/builder/src/utils/util.js b/packages/builder/src/utils/util.js index ad3d7d4d94d..042ac79659d 100644 --- a/packages/builder/src/utils/util.js +++ b/packages/builder/src/utils/util.js @@ -142,7 +142,7 @@ export const wrapSubmitSchema = (schema, keepAll = false) => { /** * 根据schema获取有顺序的properties * @param {Object} schema - * @param {Boolean} needFormat 是否需要转换返回数组,默认是 + * @param {String} containerId 相对容器id */ export const getOrderProperties = (schema = {}) => { const { properties = {} } = schema @@ -166,7 +166,8 @@ export const getOrderProperties = (schema = {}) => { const index = item['x-index'] if (typeof index === 'number') { if (!newProperties[index]) { - const _key = index > newProperties.length + 1 ? newProperties.length : index + const _key = + index > newProperties.length + 1 ? newProperties.length : index newProperties[_key] = { ...item, id: key