From e54228401c0bd9f625932baec6fe71affb5a3d60 Mon Sep 17 00:00:00 2001 From: xujiang Date: Mon, 7 Sep 2020 23:22:43 +0800 Subject: [PATCH] =?UTF-8?q?:new:=20=E6=96=B0=E5=A2=9E=E9=95=BF=E6=96=87?= =?UTF-8?q?=E6=9C=AC=E7=BB=84=E4=BB=B6,=20=E9=95=BF=E6=96=87=E6=9C=AC?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E7=9A=84typescript=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/DynamicEngine/components.tsx | 15 +- src/components/DynamicEngine/index.tsx | 1 - src/components/DynamicEngine/schema.ts | 65 ++++ src/components/DynamicEngine/template.ts | 5 + src/components/Form/BaseForm.js | 87 +++++ src/components/Form/EditorModal.js | 104 ++++++ src/components/Form/FormItems.js | 138 ++++++++ src/components/Form/baseForm.less | 10 + src/components/Form/formItems.less | 56 +++ src/components/Form/index.js | 70 ++++ src/components/Form/index.less | 14 + src/components/Icon/index.ts | 364 ++++++++++++++++++++ 12 files changed, 927 insertions(+), 2 deletions(-) create mode 100644 src/components/Form/BaseForm.js create mode 100644 src/components/Form/EditorModal.js create mode 100644 src/components/Form/FormItems.js create mode 100644 src/components/Form/baseForm.less create mode 100644 src/components/Form/formItems.less create mode 100644 src/components/Form/index.js create mode 100644 src/components/Form/index.less create mode 100644 src/components/Icon/index.ts diff --git a/src/components/DynamicEngine/components.tsx b/src/components/DynamicEngine/components.tsx index 03581b9..003a29c 100644 --- a/src/components/DynamicEngine/components.tsx +++ b/src/components/DynamicEngine/components.tsx @@ -5,6 +5,7 @@ import React from 'react'; import { HeaderConfigType, TextConfigType, + LongTextConfigType, NoticeConfigType, QRCodeConfigType, FooterConfigType, @@ -55,6 +56,18 @@ const Qrcode = memo((props: QRCodeConfigType) => { ); }); +const LongText = memo((props: LongTextConfigType) => { + const { text, fontSize, color, indent, lineHeight } = props; + return ( +
+ {text} +
+ ); +}); + const Footer = memo((props: FooterConfigType) => { const { bgColor, text, color, align, fontSize, height } = props; return ( @@ -144,4 +157,4 @@ const XProgress = memo((props: XProgressConfigType) => { ); }); -export { Header, Text, Notice, Qrcode, Footer, Image, List, XProgress }; +export { Header, Text, LongText, Notice, Qrcode, Footer, Image, List, XProgress }; diff --git a/src/components/DynamicEngine/index.tsx b/src/components/DynamicEngine/index.tsx index 10e95f7..22c5439 100644 --- a/src/components/DynamicEngine/index.tsx +++ b/src/components/DynamicEngine/index.tsx @@ -38,7 +38,6 @@ type DynamicType = { }; const DynamicEngine = memo((props: DynamicType) => { const { type, config, isTpl } = props; - console.log(config); const Dynamic = useMemo(() => { return (DynamicFunc(type) as unknown) as FC; // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/src/components/DynamicEngine/schema.ts b/src/components/DynamicEngine/schema.ts index 40003a4..997ecaa 100644 --- a/src/components/DynamicEngine/schema.ts +++ b/src/components/DynamicEngine/schema.ts @@ -9,6 +9,8 @@ export type BasicSchemaType = | 'Switch' | 'DataList' | 'Text' + | 'LongText' + | 'TextArea' | 'Color' | 'Number' | 'Select' @@ -102,6 +104,30 @@ export interface TextSchema extends SchemaBasicImplement { editData: Array>; config: TextConfigType; } +//__________________________________________ +//________________LongText________________________ +export type LongTextConfigType = { + text: string; + fontSize: number; + color: string; + indent: number; + lineHeight: number; +}; + +export type LongTextKeyType = keyof LongTextConfigType; + +export interface LongTextEditItem { + key: T; + name: string; + type: BasicSchemaType; + range?: Array; + step?: number; +} + +export interface LongTextSchema extends SchemaBasicImplement { + editData: Array>; + config: LongTextConfigType; +} //__________________________________________ //________________TAB________________________ @@ -401,6 +427,7 @@ export interface XProgressSchema extends SchemaBasicImplement { export interface SchemaType extends SchemaImplement { Carousel: CarouselSchema; Text: TextSchema; + LongText: LongTextSchema; Tab: TabSchema; Notice: NoticeSchema; Qrcode: QRCodeSchema; @@ -534,6 +561,44 @@ const schema: SchemaType = { lineHeight: 2, }, }, + LongText: { + editData: [ + { + key: 'text', + name: '文字', + type: 'TextArea', + }, + { + key: 'color', + name: '标题颜色', + type: 'Color', + }, + { + key: 'fontSize', + name: '字体大小', + type: 'Number', + }, + { + key: 'indent', + name: '首行缩进', + type: 'Number', + range: [0, 100], + }, + { + key: 'lineHeight', + name: '行高', + type: 'Number', + step: 0.1, + }, + ], + config: { + text: '我是长文本有一段故事,dooring可视化编辑器无限可能,赶快来体验吧,骚年们,奥利给~', + color: 'rgba(60,60,60,1)', + fontSize: 14, + indent: 20, + lineHeight: 1.8, + }, + }, Tab: { editData: [ { diff --git a/src/components/DynamicEngine/template.ts b/src/components/DynamicEngine/template.ts index 258afde..cf413d5 100644 --- a/src/components/DynamicEngine/template.ts +++ b/src/components/DynamicEngine/template.ts @@ -2,6 +2,7 @@ import { BasicTemplateItem } from './schema'; export type TemplateKeyType = | 'Text' + | 'LongText' | 'Carousel' | 'Tab' | 'Notice' @@ -19,6 +20,10 @@ const template: TemplateType = [ type: 'Text', h: 20, }, + { + type: 'LongText', + h: 36, + }, { type: 'Carousel', h: 82, diff --git a/src/components/Form/BaseForm.js b/src/components/Form/BaseForm.js new file mode 100644 index 0000000..277dd07 --- /dev/null +++ b/src/components/Form/BaseForm.js @@ -0,0 +1,87 @@ +import { Input, Cell, DateSelect, Radio, Select } from 'zarm'; +import styles from './baseForm.less'; + +// 维护表单控件, 提高form渲染性能 +const BaseForm = { + Text: props => { + const { label, placeholder, onChange } = props; + return ( + + + + ); + }, + Textarea: props => { + const { label, placeholder, onChange } = props; + return ( + + + + ); + }, + Number: props => { + const { label, placeholder, onChange } = props; + return ( + + + + ); + }, + MyRadio: props => { + const { label, options, onChange } = props; + return ( +
+
{label}
+ + + {options.map((item, i) => { + return ( + + {item.label} + + ); + })} + + +
+ ); + }, + Date: props => { + const { label, placeholder, onChange } = props; + return ( + + + + ); + }, + MySelect: props => { + const { label, options, onChange } = props; + return ( + + + + } + {!!item.label && ( + + + + )} + {!!item.placeholder && ( + + + + )} + {!!item.options && ( + + + + )} + + + ) + ); +}; + +export default memo(EditorModal); diff --git a/src/components/Form/FormItems.js b/src/components/Form/FormItems.js new file mode 100644 index 0000000..b9f6f63 --- /dev/null +++ b/src/components/Form/FormItems.js @@ -0,0 +1,138 @@ +import React, { memo, useState, useEffect } from 'react'; +import BaseForm from './BaseForm'; +import EditorModal from './EditorModal'; + +import { EditOutlined, MinusCircleOutlined } from '@ant-design/icons'; + +// import { Popconfirm } from 'antd'; + +import styles from './formItems.less'; + +const formTpl = [ + { + id: '1', + type: 'Text', + label: '文本', + placeholder: '请输入文本', + }, + { + id: '2', + type: 'Textarea', + label: '长文本', + placeholder: '请输入长文本请输入长文本', + }, + { + id: '3', + type: 'Number', + label: '数值', + placeholder: ' 请输入数值', + }, + { + id: '4', + type: 'MyRadio', + label: '单选框', + options: [ + { label: '选项一', value: '1' }, + { label: '选项二', value: '2' }, + ], + }, + { + id: '5', + type: 'MySelect', + label: '下拉选择框', + options: [ + { label: '选项一', value: '1' }, + { label: '选项二', value: '2' }, + { label: '选项三', value: '3' }, + ], + }, + { + id: '6', + type: 'Date', + label: '日期框', + }, +]; + +const FormItems = props => { + const { formList, onChange } = props; + const [formData, setFormData] = useState(formList || []); + const [visible, setVisible] = useState(false); + const [curItem, setCurItem] = useState(); + + const handleAddItem = item => { + let tpl = formTpl.find(v => v.type === item.type); + let newData = [...formData, tpl]; + setFormData(newData); + onChange && onChange(newData); + }; + + const handleEditItem = item => { + setVisible(true); + setCurItem(item); + }; + + const handleDelItem = item => { + let newData = formData.filter(v => v.type !== item.type); + setFormData(newData); + onChange && onChange(newData); + }; + + const handleCloseModal = () => { + setVisible(false); + }; + + const handleSaveItem = data => { + let newData = formData.map(v => (v.type === data.type ? data : v)); + setFormData(newData); + onChange && onChange(newData); + setVisible(false); + }; + return ( +
+
+ {formData.map((item, i) => { + let FormItem = BaseForm[item.type]; + return ( +
+
+ +
+
+ + + + + + +
+
+ ); + })} +
+
+

表单模版

+ {formTpl.map((item, i) => { + let FormItem = BaseForm[item.type]; + return ( +
+
+ +
+ + 添加 + +
+ ); + })} +
+ +
+ ); +}; + +export default memo(FormItems); diff --git a/src/components/Form/baseForm.less b/src/components/Form/baseForm.less new file mode 100644 index 0000000..7f78aa2 --- /dev/null +++ b/src/components/Form/baseForm.less @@ -0,0 +1,10 @@ +.radioWrap { + margin-bottom: 10px; + .radioTitle { + padding: 6px 16px; + font-size: 15px; + } + .radioItem { + margin-top: 10px; + } +} diff --git a/src/components/Form/formItems.less b/src/components/Form/formItems.less new file mode 100644 index 0000000..bdf18ea --- /dev/null +++ b/src/components/Form/formItems.less @@ -0,0 +1,56 @@ +.formItemWrap { + .editForm { + .formItem { + position: relative; + &:hover { + .operationWrap { + display: inline-block; + } + } + .operationWrap { + position: absolute; + display: none; + right: 0; + top: 16px; + box-shadow: 0 0 20px #fff; + background-color: #fff; + .operationBtn { + margin-right: 15px; + display: inline-block; + cursor: pointer; + } + } + } + } + .formTpl { + margin-top: 12px; + border-top: 1px dashed #ccc; + padding-top: 16px; + .formItem { + position: relative; + border: 1px solid #ccc; + margin-bottom: 2px; + .disClick { + pointer-events: none; + } + &:hover { + border-color: #2f54eb; + .addBtn { + display: inline-block; + } + } + .addBtn { + position: absolute; + right: 0; + top: 50%; + transform: translateY(-50%); + display: none; + padding: 3px 6px; + color: #fff; + border-radius: 3px; + background-color: #2f54eb; + cursor: pointer; + } + } + } +} diff --git a/src/components/Form/index.js b/src/components/Form/index.js new file mode 100644 index 0000000..37b9e1d --- /dev/null +++ b/src/components/Form/index.js @@ -0,0 +1,70 @@ +import React, { memo, useState, useEffect } from 'react'; +import { Button } from 'zarm'; +import BaseForm from './BaseForm'; +import req from 'utils/req'; +import styles from './index.less'; + +function unParams(params = '?a=1&b=2&c=3') { + let obj = {}; + params && + params.replace(/((\w*)=([\.a-z0-9A-Z]*)?)?/g, (m, a, b, c) => { + if (b || c) obj[b] = c; + }); + return obj; +} +const FormComponent = props => { + const { title, bgColor, fontSize, titColor, btnColor, btnTextColor, api, formControls } = props; + + const formData = {}; + + const handleChange = (item, v) => { + if (item.options) { + formData[item.label] = v[0].label; + return; + } + formData[item.label] = v; + }; + + const handleSubmit = () => { + if (api) { + fetch(api, { + body: JSON.stringify(formData), + cache: 'no-cache', + headers: { + 'content-type': 'application/json', + }, + method: 'POST', + mode: 'cors', + }); + } + }; + + return ( +
+ {title && ( +
+ {title} +
+ )} +
+ {formControls.map(item => { + const FormItem = BaseForm[item.type]; + return ; + })} +
+ +
+
+
+ ); +}; + +export default memo(FormComponent); diff --git a/src/components/Form/index.less b/src/components/Form/index.less new file mode 100644 index 0000000..d106cbb --- /dev/null +++ b/src/components/Form/index.less @@ -0,0 +1,14 @@ +.formWrap { + margin: 10px; + padding: 20px 16px; + border-radius: 6px; + background-color: #fff; + box-shadow: 0 2px 6px #f0f0f0; + .title { + padding-bottom: 20px; + text-align: center; + font-size: 18px; + } + .formContent { + } +} diff --git a/src/components/Icon/index.ts b/src/components/Icon/index.ts new file mode 100644 index 0000000..b2ffe99 --- /dev/null +++ b/src/components/Icon/index.ts @@ -0,0 +1,364 @@ +export type AntdIconType = + | 'max' + | 'required' + | 'default' + | 'high' + | 'low' + | 'disabled' + | 'start' + | 'open' + | 'media' + | 'hidden' + | 'cite' + | 'data' + | 'dir' + | 'form' + | 'label' + | 'slot' + | 'span' + | 'style' + | 'summary' + | 'title' + | 'pattern' + | 'async' + | 'defer' + | 'manifest' + | 'color' + | 'content' + | 'size' + | 'wrap' + | 'multiple' + | 'height' + | 'rotate' + | 'translate' + | 'width' + | 'prefix' + | 'src' + | 'children' + | 'key' + | 'list' + | 'step' + | 'aria-label' + | 'spin' + | 'accept' + | 'acceptCharset' + | 'action' + | 'allowFullScreen' + | 'allowTransparency' + | 'alt' + | 'as' + | 'autoComplete' + | 'autoFocus' + | 'autoPlay' + | 'capture' + | 'cellPadding' + | 'cellSpacing' + | 'charSet' + | 'challenge' + | 'checked' + | 'classID' + | 'cols' + | 'colSpan' + | 'controls' + | 'coords' + | 'crossOrigin' + | 'dateTime' + | 'download' + | 'encType' + | 'formAction' + | 'formEncType' + | 'formMethod' + | 'formNoValidate' + | 'formTarget' + | 'frameBorder' + | 'headers' + | 'href' + | 'hrefLang' + | 'htmlFor' + | 'httpEquiv' + | 'integrity' + | 'keyParams' + | 'keyType' + | 'kind' + | 'loop' + | 'marginHeight' + | 'marginWidth' + | 'maxLength' + | 'mediaGroup' + | 'method' + | 'min' + | 'minLength' + | 'muted' + | 'name' + | 'nonce' + | 'noValidate' + | 'optimum' + | 'placeholder' + | 'playsInline' + | 'poster' + | 'preload' + | 'readOnly' + | 'rel' + | 'reversed' + | 'rows' + | 'rowSpan' + | 'sandbox' + | 'scope' + | 'scoped' + | 'scrolling' + | 'seamless' + | 'selected' + | 'shape' + | 'sizes' + | 'srcDoc' + | 'srcLang' + | 'srcSet' + | 'target' + | 'type' + | 'useMap' + | 'value' + | 'wmode' + | 'defaultChecked' + | 'defaultValue' + | 'suppressContentEditableWarning' + | 'suppressHydrationWarning' + | 'accessKey' + | 'className' + | 'contentEditable' + | 'contextMenu' + | 'draggable' + | 'id' + | 'lang' + | 'spellCheck' + | 'tabIndex' + | 'radioGroup' + | 'role' + | 'about' + | 'datatype' + | 'inlist' + | 'property' + | 'resource' + | 'typeof' + | 'vocab' + | 'autoCapitalize' + | 'autoCorrect' + | 'autoSave' + | 'itemProp' + | 'itemScope' + | 'itemType' + | 'itemID' + | 'itemRef' + | 'results' + | 'security' + | 'unselectable' + | 'inputMode' + | 'is' + | 'aria-activedescendant' + | 'aria-atomic' + | 'aria-autocomplete' + | 'aria-busy' + | 'aria-checked' + | 'aria-colcount' + | 'aria-colindex' + | 'aria-colspan' + | 'aria-controls' + | 'aria-current' + | 'aria-describedby' + | 'aria-details' + | 'aria-disabled' + | 'aria-dropeffect' + | 'aria-errormessage' + | 'aria-expanded' + | 'aria-flowto' + | 'aria-grabbed' + | 'aria-haspopup' + | 'aria-hidden' + | 'aria-invalid' + | 'aria-keyshortcuts' + | 'aria-labelledby' + | 'aria-level' + | 'aria-live' + | 'aria-modal' + | 'aria-multiline' + | 'aria-multiselectable' + | 'aria-orientation' + | 'aria-owns' + | 'aria-placeholder' + | 'aria-posinset' + | 'aria-pressed' + | 'aria-readonly' + | 'aria-relevant' + | 'aria-required' + | 'aria-roledescription' + | 'aria-rowcount' + | 'aria-rowindex' + | 'aria-rowspan' + | 'aria-selected' + | 'aria-setsize' + | 'aria-sort' + | 'aria-valuemax' + | 'aria-valuemin' + | 'aria-valuenow' + | 'aria-valuetext' + | 'dangerouslySetInnerHTML' + | 'onCopy' + | 'onCopyCapture' + | 'onCut' + | 'onCutCapture' + | 'onPaste' + | 'onPasteCapture' + | 'onCompositionEnd' + | 'onCompositionEndCapture' + | 'onCompositionStart' + | 'onCompositionStartCapture' + | 'onCompositionUpdate' + | 'onCompositionUpdateCapture' + | 'onFocus' + | 'onFocusCapture' + | 'onBlur' + | 'onBlurCapture' + | 'onChange' + | 'onChangeCapture' + | 'onBeforeInput' + | 'onBeforeInputCapture' + | 'onInput' + | 'onInputCapture' + | 'onReset' + | 'onResetCapture' + | 'onSubmit' + | 'onSubmitCapture' + | 'onInvalid' + | 'onInvalidCapture' + | 'onLoad' + | 'onLoadCapture' + | 'onError' + | 'onErrorCapture' + | 'onKeyDown' + | 'onKeyDownCapture' + | 'onKeyPress' + | 'onKeyPressCapture' + | 'onKeyUp' + | 'onKeyUpCapture' + | 'onAbort' + | 'onAbortCapture' + | 'onCanPlay' + | 'onCanPlayCapture' + | 'onCanPlayThrough' + | 'onCanPlayThroughCapture' + | 'onDurationChange' + | 'onDurationChangeCapture' + | 'onEmptied' + | 'onEmptiedCapture' + | 'onEncrypted' + | 'onEncryptedCapture' + | 'onEnded' + | 'onEndedCapture' + | 'onLoadedData' + | 'onLoadedDataCapture' + | 'onLoadedMetadata' + | 'onLoadedMetadataCapture' + | 'onLoadStart' + | 'onLoadStartCapture' + | 'onPause' + | 'onPauseCapture' + | 'onPlay' + | 'onPlayCapture' + | 'onPlaying' + | 'onPlayingCapture' + | 'onProgress' + | 'onProgressCapture' + | 'onRateChange' + | 'onRateChangeCapture' + | 'onSeeked' + | 'onSeekedCapture' + | 'onSeeking' + | 'onSeekingCapture' + | 'onStalled' + | 'onStalledCapture' + | 'onSuspend' + | 'onSuspendCapture' + | 'onTimeUpdate' + | 'onTimeUpdateCapture' + | 'onVolumeChange' + | 'onVolumeChangeCapture' + | 'onWaiting' + | 'onWaitingCapture' + | 'onAuxClick' + | 'onAuxClickCapture' + | 'onClick' + | 'onClickCapture' + | 'onContextMenu' + | 'onContextMenuCapture' + | 'onDoubleClick' + | 'onDoubleClickCapture' + | 'onDrag' + | 'onDragCapture' + | 'onDragEnd' + | 'onDragEndCapture' + | 'onDragEnter' + | 'onDragEnterCapture' + | 'onDragExit' + | 'onDragExitCapture' + | 'onDragLeave' + | 'onDragLeaveCapture' + | 'onDragOver' + | 'onDragOverCapture' + | 'onDragStart' + | 'onDragStartCapture' + | 'onDrop' + | 'onDropCapture' + | 'onMouseDown' + | 'onMouseDownCapture' + | 'onMouseEnter' + | 'onMouseLeave' + | 'onMouseMove' + | 'onMouseMoveCapture' + | 'onMouseOut' + | 'onMouseOutCapture' + | 'onMouseOver' + | 'onMouseOverCapture' + | 'onMouseUp' + | 'onMouseUpCapture' + | 'onSelect' + | 'onSelectCapture' + | 'onTouchCancel' + | 'onTouchCancelCapture' + | 'onTouchEnd' + | 'onTouchEndCapture' + | 'onTouchMove' + | 'onTouchMoveCapture' + | 'onTouchStart' + | 'onTouchStartCapture' + | 'onPointerDown' + | 'onPointerDownCapture' + | 'onPointerMove' + | 'onPointerMoveCapture' + | 'onPointerUp' + | 'onPointerUpCapture' + | 'onPointerCancel' + | 'onPointerCancelCapture' + | 'onPointerEnter' + | 'onPointerEnterCapture' + | 'onPointerLeave' + | 'onPointerLeaveCapture' + | 'onPointerOver' + | 'onPointerOverCapture' + | 'onPointerOut' + | 'onPointerOutCapture' + | 'onGotPointerCapture' + | 'onGotPointerCaptureCapture' + | 'onLostPointerCapture' + | 'onLostPointerCaptureCapture' + | 'onScroll' + | 'onScrollCapture' + | 'onWheel' + | 'onWheelCapture' + | 'onAnimationStart' + | 'onAnimationStartCapture' + | 'onAnimationEnd' + | 'onAnimationEndCapture' + | 'onAnimationIteration' + | 'onAnimationIterationCapture' + | 'onTransitionEnd' + | 'onTransitionEndCapture' + | 'twoToneColor';