From f9ba5907ddff56da7c38b1c7d5a9c5ba6aadfa05 Mon Sep 17 00:00:00 2001
From: king <18310653075@163.com>
Date: 星期二, 19 一月 2021 17:10:19 +0800
Subject: [PATCH] 2021-01-19

---
 src/tabviews/custom/components/editor/braft-editor/index.jsx               |  196 ++++++++++
 src/menu/components/group/groupcomponents/index.jsx                        |    1 
 src/menu/components/editor/braft-editor/wrapsetting/index.scss             |    7 
 src/tabviews/custom/components/share/braftContent/index.scss               |   25 +
 src/menu/datasource/index.jsx                                              |    2 
 src/menu/components/tabs/tabcomponents/index.jsx                           |    1 
 src/views/billprint/index.jsx                                              |   15 
 src/menu/menushell/card.jsx                                                |    3 
 src/menu/components/editor/braft-editor/index.scss                         |   36 +
 src/views/menudesign/index.jsx                                             |    2 
 src/assets/css/main.scss                                                   |    4 
 src/menu/components/share/usercomponent/index.jsx                          |    1 
 src/tabviews/custom/components/share/tabtransfer/index.jsx                 |    9 
 src/menu/components/editor/braft-editor/wrapsetting/index.jsx              |   83 ++++
 src/components/editor/index.jsx                                            |    2 
 src/tabviews/custom/components/group/normal-group/index.jsx                |    9 
 src/menu/components/editor/braft-editor/editorcontent/index.scss           |   14 
 src/menu/components/editor/braft-editor/wrapsetting/settingform/index.jsx  |  199 ++++++++++
 src/menu/components/editor/braft-editor/wrapsetting/settingform/index.scss |   15 
 src/menu/components/group/groupcomponents/card.jsx                         |    3 
 /dev/null                                                                  |   34 -
 src/tabviews/custom/components/editor/braft-editor/index.scss              |   76 ++++
 src/tabviews/custom/components/share/braftContent/index.jsx                |   58 +++
 src/menu/modelsource/option.jsx                                            |    2 
 src/menu/components/editor/braft-editor/editorcontent/index.jsx            |   82 ++++
 src/tabviews/custom/index.jsx                                              |   13 
 src/menu/components/editor/braft-editor/index.jsx                          |  196 ++++++++++
 src/menu/components/tabs/tabcomponents/card.jsx                            |    3 
 src/menu/menushell/index.jsx                                               |    1 
 src/assets/mobimg/editor.png                                               |    0 
 src/menu/popview/index.jsx                                                 |    2 
 31 files changed, 1,050 insertions(+), 44 deletions(-)

diff --git a/src/assets/css/main.scss b/src/assets/css/main.scss
index 6deb445..8b7caf8 100644
--- a/src/assets/css/main.scss
+++ b/src/assets/css/main.scss
@@ -258,7 +258,7 @@
 .ant-modal.popview-modal {
   top: 70px;
   .ant-modal-body {
-    min-height: 250px;
+    min-height: 200px;
     max-height: calc(100vh - 210px);
     overflow-y: auto;
   }
@@ -282,7 +282,7 @@
     top: 70px;
   }
   .ant-modal-body {
-    min-height: 250px;
+    min-height: 200px;
     max-height: calc(100vh - 210px);
     overflow-y: auto;
   }
diff --git a/src/assets/mobimg/editor.png b/src/assets/mobimg/editor.png
new file mode 100644
index 0000000..993dac9
--- /dev/null
+++ b/src/assets/mobimg/editor.png
Binary files differ
diff --git a/src/components/editor/index.jsx b/src/components/editor/index.jsx
index 2c0bd2b..a94d12e 100644
--- a/src/components/editor/index.jsx
+++ b/src/components/editor/index.jsx
@@ -38,6 +38,8 @@
 
     if (this.props['data-__meta']) {
       initVal = this.props['data-__meta'].initialValue || null
+    } else if (this.props.defaultValue) {
+      initVal = this.props.defaultValue || null
     }
 
     if (this.props.Item && this.props.Item.encryption === 'true') {
diff --git a/src/menu/components/editor/braft-editor/editorcontent/index.jsx b/src/menu/components/editor/braft-editor/editorcontent/index.jsx
new file mode 100644
index 0000000..1548854
--- /dev/null
+++ b/src/menu/components/editor/braft-editor/editorcontent/index.jsx
@@ -0,0 +1,82 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Icon, Modal } from 'antd'
+
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import asyncComponent from '@/utils/asyncComponent'
+import './index.scss'
+
+const Editor = asyncComponent(() => import('@/components/editor'))
+
+class DataSource extends Component {
+  static propTpyes = {
+    config: PropTypes.any,
+    updateConfig: PropTypes.func
+  }
+
+  state = {
+    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    visible: false,
+    html: null
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  trigger = () => {
+    const { config } = this.props
+
+    this.setState({
+      visible: true,
+      html: config.html || null
+    })
+  }
+
+  verifySubmit = () => {
+    const { config } = this.props
+    const { html } = this.state
+
+    this.setState({
+      visible: false
+    })
+    this.props.updateConfig({...config, html})
+  }
+
+  onChange = (val) => {
+    this.setState({
+      html: val
+    })
+  }
+
+  render () {
+    const { config } = this.props
+    const { visible, dict, html } = this.state
+
+    if (!config) return null
+
+    return (
+      <div className="model-menu-edit-content-wrap">
+        {config.wrap.datatype === 'static' ? <Icon title="鍐呭缂栬緫" type="form" onClick={() => this.trigger()} /> : null}
+        {config.wrap.datatype !== 'static' ? <Icon title="鍐呭缂栬緫" style={{color: '#eeeeee', cursor: 'not-allowed'}} type="form"/> : null}
+        <Modal
+          wrapClassName="popview-modal model-menu-edit-content-form"
+          title="鍐呭缂栬緫"
+          visible={visible}
+          width={950}
+          maskClosable={false}
+          okText={dict['model.submit']}
+          onOk={this.verifySubmit}
+          onCancel={() => { this.setState({ visible: false }) }}
+          destroyOnClose
+        >
+          <Editor defaultValue={html} onChange={this.onChange} />
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default DataSource
\ No newline at end of file
diff --git a/src/menu/components/editor/braft-editor/editorcontent/index.scss b/src/menu/components/editor/braft-editor/editorcontent/index.scss
new file mode 100644
index 0000000..dc27e8c
--- /dev/null
+++ b/src/menu/components/editor/braft-editor/editorcontent/index.scss
@@ -0,0 +1,14 @@
+.model-menu-edit-content-wrap {
+  display: inline-block;
+
+  >.anticon-form {
+    color: purple;
+  }
+}
+.model-menu-edit-content-form {
+  .normal-braft-editor {
+    border: 1px solid #d9d9d9;
+    border-radius: 4px;
+    overflow-x: hidden;
+  }
+}
\ No newline at end of file
diff --git a/src/menu/components/editor/braft-editor/index.jsx b/src/menu/components/editor/braft-editor/index.jsx
new file mode 100644
index 0000000..708d546
--- /dev/null
+++ b/src/menu/components/editor/braft-editor/index.jsx
@@ -0,0 +1,196 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import {connect} from 'react-redux'
+import { is, fromJS } from 'immutable'
+import { Icon, Popover } from 'antd'
+
+import asyncComponent from '@/utils/asyncComponent'
+import asyncIconComponent from '@/utils/asyncIconComponent'
+
+import MKEmitter from '@/utils/events.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+
+import './index.scss'
+
+const SettingComponent = asyncIconComponent(() => import('@/menu/datasource'))
+const NormalHeader = asyncComponent(() => import('@/menu/components/share/normalheader'))
+const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
+const UserComponent = asyncIconComponent(() => import('@/menu/components/share/usercomponent'))
+const WrapComponent = asyncIconComponent(() => import('./wrapsetting'))
+const EditorContent = asyncIconComponent(() => import('./editorcontent'))
+const BraftContent = asyncComponent(() => import('@/tabviews/custom/components/share/braftContent'))
+
+class TableCardEditComponent extends Component {
+  static propTpyes = {
+    card: PropTypes.object,
+    deletecomponent: PropTypes.func,
+    updateConfig: PropTypes.func,
+  }
+
+  state = {
+    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    card: null,
+    back: false
+  }
+
+  UNSAFE_componentWillMount () {
+    const { card } = this.props
+
+    if (card.isNew) {
+      let _card = {
+        uuid: card.uuid,
+        type: card.type,
+        floor: card.floor,
+        tabId: card.tabId || '',
+        parentId: card.parentId || '',
+        dataName: card.dataName || '',
+        format: 'object',   // 缁勪欢灞炴�� - 鏁版嵁鏍煎紡
+        pageable: false,    // 缁勪欢灞炴�� - 鏄惁鍙垎椤�
+        switchable: false,  // 缁勪欢灞炴�� - 鏁版嵁鏄惁鍙垏鎹�
+        width: card.width || 24,
+        name: card.name,
+        subtype: card.subtype,
+        setting: { interType: 'system' },
+        wrap: { name: card.name, width: card.width || 24, encryption: 'true' },
+        style: { marginLeft: '8px', marginRight: '8px', marginTop: '8px', marginBottom: '8px' },
+        headerStyle: { fontSize: '16px', borderBottomWidth: '1px', borderBottomColor: '#e8e8e8' },
+        columns: [],
+        scripts: [],
+        html: ''
+      }
+
+      if (card.config) {
+        let config = fromJS(card.config).toJS()
+
+        _card.wrap = config.wrap
+        _card.wrap.name = card.name
+        _card.style = config.style
+        _card.headerStyle = config.headerStyle
+        _card.html = config.html
+      }
+      
+      this.setState({
+        card: _card
+      })
+      this.props.updateConfig(_card)
+    } else {
+      this.setState({
+        card: fromJS(card).toJS()
+      })
+    }
+  }
+
+  componentDidMount () {
+    MKEmitter.addListener('submitStyle', this.getStyle)
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState)) || (!this.props.menu && nextProps.menu)
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('submitStyle', this.getStyle)
+  }
+
+  /**
+   * @description 鍗$墖琛屽灞備俊鎭洿鏂帮紙鏁版嵁婧愶紝鏍峰紡绛夛級
+   */
+  updateComponent = (component) => {
+    this.setState({
+      card: component
+    })
+
+    component.width = component.wrap.width
+    component.name = component.wrap.name
+
+    this.props.updateConfig(component)
+  }
+
+  changeStyle = () => {
+    const { card } = this.state
+
+    MKEmitter.emit('changeStyle', [card.uuid], ['background', 'border', 'padding', 'margin'], card.style)
+  }
+
+  getStyle = (comIds, style) => {
+    const { card } = this.state
+
+    if (comIds[0] !== card.uuid) return
+
+    let _card = {}
+    if (comIds.length === 1) {
+      _card = {...card, style}
+    } else {
+      return
+    }
+
+    this.setState({
+      card: _card
+    })
+    
+    this.props.updateConfig(_card)
+  }
+
+  /**
+   * @description 鏇存柊鎼滅储鏉′欢閰嶇疆淇℃伅
+   */
+  updateconfig = (config) => {
+    this.setState({
+      card: config
+    })
+    this.props.updateConfig(config)
+  }
+
+  clickComponent = (e) => {
+    if (sessionStorage.getItem('style-control') === 'true' || sessionStorage.getItem('style-control') === 'component') {
+      e.stopPropagation()
+      MKEmitter.emit('clickComponent', this.state.card)
+    }
+  }
+
+  render() {
+    const { card } = this.state
+    return (
+      <div className="menu-normal-editor-box" style={{...card.style}} onClick={this.clickComponent} id={card.uuid}>
+        <NormalHeader defaultshow="hidden" hideSearch="true" config={card} updateComponent={this.updateComponent}/>
+        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
+          <div className="mk-popover-control">
+            <WrapComponent config={card} updateConfig={this.updateComponent} />
+            <CopyComponent type="normaltable" card={card}/>
+            <Icon className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle} type="font-colors" />
+            <UserComponent config={card}/>
+            <Icon className="close" title="鍒犻櫎缁勪欢" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
+            <EditorContent config={card} updateConfig={this.updateComponent}/>
+            {card.wrap.datatype !== 'static' ? <SettingComponent config={card} updateConfig={this.updateComponent} /> : null}
+            {card.wrap.datatype === 'static' ? <Icon style={{color: '#eeeeee', cursor: 'not-allowed'}} type="setting"/> : null}
+          </div>
+        } trigger="hover">
+          <Icon type="tool" />
+        </Popover>
+        <BraftContent
+          value={card.wrap.datatype !== 'static' ? '<p class="empty-content">瀵屾枃鏈�</p>' : card.html}
+          encryption="false"
+        />
+      </div>
+    )
+  }
+}
+
+const mapStateToProps = (state) => {
+  return {
+    menu: state.customMenu
+  }
+}
+
+const mapDispatchToProps = () => {
+  return {}
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(TableCardEditComponent)
\ No newline at end of file
diff --git a/src/menu/components/editor/braft-editor/index.scss b/src/menu/components/editor/braft-editor/index.scss
new file mode 100644
index 0000000..ee47b6d
--- /dev/null
+++ b/src/menu/components/editor/braft-editor/index.scss
@@ -0,0 +1,36 @@
+.menu-normal-editor-box {
+  position: relative;
+  box-sizing: border-box;
+  background: #ffffff;
+  background-position: center center;
+  background-repeat: no-repeat;
+  background-size: cover;
+  min-height: 100px;
+
+  .anticon-tool {
+    position: absolute;
+    z-index: 2;
+    font-size: 16px;
+    right: 1px;
+    top: 1px;
+    cursor: pointer;
+    padding: 5px;
+    background: rgba(255, 255, 255, 0.55);
+  }
+  .empty-content {
+    text-align: center;
+    font-size: 30px;
+    margin: 0;
+    line-height: 90px;
+    color: #bcbcbc;
+  }
+}
+.menu-normal-table-edit-box::after {
+  display: block;
+  content: ' ';
+  clear: both;
+}
+.menu-normal-table-edit-box:hover {
+  z-index: 1;
+  box-shadow: 0px 0px 4px #1890ff;
+}
diff --git a/src/menu/components/editor/braft-editor/wrapsetting/index.jsx b/src/menu/components/editor/braft-editor/wrapsetting/index.jsx
new file mode 100644
index 0000000..c949c28
--- /dev/null
+++ b/src/menu/components/editor/braft-editor/wrapsetting/index.jsx
@@ -0,0 +1,83 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Icon, Modal } from 'antd'
+
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import SettingForm from './settingform'
+import './index.scss'
+
+class DataSource extends Component {
+  static propTpyes = {
+    config: PropTypes.any,
+    updateConfig: PropTypes.func
+  }
+
+  state = {
+    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    visible: false,
+    wrap: null
+  }
+
+  UNSAFE_componentWillMount () {
+    const { config } = this.props
+
+    this.setState({wrap: fromJS(config.wrap).toJS()})
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  editDataSource = () => {
+    this.setState({
+      visible: true
+    })
+  }
+
+  verifySubmit = () => {
+    const { config } = this.props
+
+    this.verifyRef.handleConfirm().then(res => {
+
+      this.setState({
+        wrap: res,
+        visible: false
+      })
+      this.props.updateConfig({...config, wrap: res})
+    })
+  }
+
+  render () {
+    const { config } = this.props
+    const { visible, dict, wrap } = this.state
+
+    return (
+      <div className="model-menu-setting-wrap">
+        <Icon type="edit" onClick={() => this.editDataSource()} />
+        <Modal
+          wrapClassName="popview-modal"
+          title="瀵屾枃鏈缃�"
+          visible={visible}
+          width={700}
+          maskClosable={false}
+          okText={dict['model.submit']}
+          onOk={this.verifySubmit}
+          onCancel={() => { this.setState({ visible: false }) }}
+          destroyOnClose
+        >
+          <SettingForm
+            dict={dict}
+            wrap={wrap}
+            config={config}
+            inputSubmit={this.verifySubmit}
+            wrappedComponentRef={(inst) => this.verifyRef = inst}
+          />
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default DataSource
\ No newline at end of file
diff --git a/src/menu/components/editor/braft-editor/wrapsetting/index.scss b/src/menu/components/editor/braft-editor/wrapsetting/index.scss
new file mode 100644
index 0000000..04372e6
--- /dev/null
+++ b/src/menu/components/editor/braft-editor/wrapsetting/index.scss
@@ -0,0 +1,7 @@
+.model-menu-setting-wrap {
+  display: inline-block;
+
+  >.anticon-edit {
+    color: #1890ff;
+  }
+}
\ No newline at end of file
diff --git a/src/menu/components/editor/braft-editor/wrapsetting/settingform/index.jsx b/src/menu/components/editor/braft-editor/wrapsetting/settingform/index.jsx
new file mode 100644
index 0000000..b93fffd
--- /dev/null
+++ b/src/menu/components/editor/braft-editor/wrapsetting/settingform/index.jsx
@@ -0,0 +1,199 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Input, Radio, Tooltip, Icon, InputNumber, Select } from 'antd'
+
+import './index.scss'
+
+class SettingForm extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,      // 瀛楀吀椤�
+    config: PropTypes.object,    // 鍗$墖琛屼俊鎭�
+    wrap: PropTypes.object,      // 鏁版嵁婧愰厤缃�
+    inputSubmit: PropTypes.func  // 鍥炶溅浜嬩欢
+  }
+
+  state = {
+    roleList: [],
+    datatype: this.props.wrap.datatype || 'dynamic'
+  }
+
+  UNSAFE_componentWillMount () {
+    let roleList = sessionStorage.getItem('sysRoles')
+    if (roleList) {
+      try {
+        roleList = JSON.parse(roleList)
+      } catch {
+        roleList = []
+      }
+    } else {
+      roleList = []
+    }
+
+    this.setState({roleList})
+  }
+
+  handleConfirm = () => {
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          resolve(values)
+        } else {
+          reject(err)
+        }
+      })
+    })
+  }
+
+  handleSubmit = (e) => {
+    e.preventDefault()
+
+    if (this.props.inputSubmit) {
+      this.props.inputSubmit()
+    }
+  }
+
+  changeDataType = (e) => {
+    this.setState({datatype: e.target.value})
+  }
+
+  render() {
+    const { wrap, config } = this.props
+    const { getFieldDecorator } = this.props.form
+    const { roleList, datatype } = this.state
+
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <div className="model-menu-setting-form">
+        <Form {...formItemLayout}>
+          <Row gutter={24}>
+            <Col span={12}>
+              <Form.Item label="鏍囬">
+                {getFieldDecorator('title', {
+                  initialValue: wrap.title || ''
+                })(<Input placeholder={''} autoComplete="off" onPressEnter={this.handleSubmit} />)}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="鐢ㄤ簬缁勪欢闂寸殑鍖哄垎銆�">
+                  <Icon type="question-circle" />
+                  缁勪欢鍚嶇О
+                </Tooltip>
+              }>
+                {getFieldDecorator('name', {
+                  initialValue: wrap.name,
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.input'] + '缁勪欢鍚嶇О!'
+                    }
+                  ]
+                })(<Input placeholder={''} autoComplete="off" onPressEnter={this.handleSubmit} />)}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="鏍呮牸甯冨眬锛屾瘡琛岀瓑鍒嗕负24鍒椼��">
+                  <Icon type="question-circle" />
+                  瀹藉害
+                </Tooltip>
+              }>
+                {getFieldDecorator('width', {
+                  initialValue: wrap.width || 24,
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.input'] + '瀹藉害!'
+                    }
+                  ]
+                })(<InputNumber min={1} max={24} precision={0} onPressEnter={this.handleSubmit} />)}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="閫夋嫨闈欐�佸�硷紝鏃犻渶閰嶇疆鏁版嵁婧愩��">
+                  <Icon type="question-circle" />
+                  鏁版嵁鏉ユ簮
+                </Tooltip>
+              }>
+                {getFieldDecorator('datatype', {
+                  initialValue: datatype
+                })(
+                  <Radio.Group onChange={this.changeDataType}>
+                    <Radio value="dynamic">鍔ㄦ��</Radio>
+                    <Radio value="static">闈欐��</Radio>
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col>
+            {datatype === 'dynamic' ? <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="閫夋嫨鍔ㄦ�佸�兼椂锛岄渶璁剧疆鏂囨湰瀛楁鎵嶅彲鐢熸晥銆�">
+                  <Icon type="question-circle" />
+                  鏂囨湰瀛楁
+                </Tooltip>
+              }>
+                {getFieldDecorator('field', {
+                  initialValue: wrap.field || ''
+                })(
+                  <Select>
+                    {config.columns.map(option =>
+                      <Select.Option key={option.uuid} value={option.field}>{option.label}</Select.Option>
+                    )}
+                  </Select>
+                )}
+              </Form.Item>
+            </Col> : null}
+            {datatype === 'dynamic' ? <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="浠庢暟鎹簮鑾峰彇鐨勬暟鎹槸鍚﹂渶瑕佽В鐮併��">
+                  <Icon type="question-circle" />
+                  鏁版嵁瑙g爜
+                </Tooltip>
+              }>
+                {getFieldDecorator('encryption', {
+                  initialValue: wrap.encryption || 'true'
+                })(
+                  <Radio.Group>
+                    <Radio value="true">鏄�</Radio>
+                    <Radio value="false">鍚�</Radio>
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col> : null}
+            <Col span={12}>
+              <Form.Item label="榛戝悕鍗�">
+                {getFieldDecorator('blacklist', {
+                  initialValue: wrap.blacklist || []
+                })(
+                  <Select
+                    showSearch
+                    mode="multiple"
+                    filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                  >
+                    {roleList.map(option =>
+                      <Select.Option key={option.uuid} value={option.value}>{option.text}</Select.Option>
+                    )}
+                  </Select>
+                )}
+              </Form.Item>
+            </Col>
+          </Row>
+        </Form>
+      </div>
+    )
+  }
+}
+
+export default Form.create()(SettingForm)
\ No newline at end of file
diff --git a/src/menu/components/editor/braft-editor/wrapsetting/settingform/index.scss b/src/menu/components/editor/braft-editor/wrapsetting/settingform/index.scss
new file mode 100644
index 0000000..c530b18
--- /dev/null
+++ b/src/menu/components/editor/braft-editor/wrapsetting/settingform/index.scss
@@ -0,0 +1,15 @@
+.model-menu-setting-form {
+  position: relative;
+
+  .anticon-question-circle {
+    color: #c49f47;
+    margin-right: 3px;
+  }
+  .ant-input-number {
+    width: 100%;
+  }
+  .color-sketch-block {
+    position: relative;
+    top: 7px;
+  }
+}
\ No newline at end of file
diff --git a/src/menu/components/group/groupcomponents/card.jsx b/src/menu/components/group/groupcomponents/card.jsx
index ced290d..99d3e95 100644
--- a/src/menu/components/group/groupcomponents/card.jsx
+++ b/src/menu/components/group/groupcomponents/card.jsx
@@ -10,6 +10,7 @@
 const PropCard = asyncComponent(() => import('@/menu/components/card/prop-card'))
 const TableCard = asyncComponent(() => import('@/menu/components/card/table-card'))
 const NormalTable = asyncComponent(() => import('@/menu/components/table/normal-table'))
+const BraftEditor = asyncComponent(() => import('@/menu/components/editor/braft-editor'))
 
 const Card = ({ id, card, moveCard, findCard, delCard, updateConfig }) => {
   const originalIndex = findCard(id).index
@@ -57,6 +58,8 @@
       return (<TableCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'table' && card.subtype === 'normaltable') {
       return (<NormalTable card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'editor') {
+      return (<BraftEditor card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     }
   }
 
diff --git a/src/menu/components/group/groupcomponents/index.jsx b/src/menu/components/group/groupcomponents/index.jsx
index f3de3c9..7a8719e 100644
--- a/src/menu/components/group/groupcomponents/index.jsx
+++ b/src/menu/components/group/groupcomponents/index.jsx
@@ -103,6 +103,7 @@
         line: '鎶樼嚎鍥�',
         pie: '楗煎浘',
         table: '琛ㄦ牸',
+        editor: '瀵屾枃鏈�',
         card: '鍗$墖'
       }
       let i = 1
diff --git a/src/menu/components/share/usercomponent/index.jsx b/src/menu/components/share/usercomponent/index.jsx
index fd071da..cff1df6 100644
--- a/src/menu/components/share/usercomponent/index.jsx
+++ b/src/menu/components/share/usercomponent/index.jsx
@@ -53,6 +53,7 @@
     _config.search = config.search || []
     _config.cols = config.cols || []
     _config.plot = config.plot || {}
+    _config.html = config.html || ''
 
     _config.width = _config.wrap.width || _config.plot.width || config.width || 24
 
diff --git a/src/menu/components/tabs/tabcomponents/card.jsx b/src/menu/components/tabs/tabcomponents/card.jsx
index 978f69a..416ca65 100644
--- a/src/menu/components/tabs/tabcomponents/card.jsx
+++ b/src/menu/components/tabs/tabcomponents/card.jsx
@@ -13,6 +13,7 @@
 const TableCard = asyncComponent(() => import('@/menu/components/card/table-card'))
 const NormalTable = asyncComponent(() => import('@/menu/components/table/normal-table'))
 const NormalGroup = asyncComponent(() => import('@/menu/components/group/normal-group'))
+const BraftEditor = asyncComponent(() => import('@/menu/components/editor/braft-editor'))
 
 const Card = ({ id, card, moveCard, findCard, delCard, updateConfig }) => {
   const originalIndex = findCard(id).index
@@ -66,6 +67,8 @@
       return (<NormalTable card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'group' && card.subtype === 'normalgroup') {
       return (<NormalGroup group={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'editor') {
+      return (<BraftEditor card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     }
   }
 
diff --git a/src/menu/components/tabs/tabcomponents/index.jsx b/src/menu/components/tabs/tabcomponents/index.jsx
index ece6a40..6bf8943 100644
--- a/src/menu/components/tabs/tabcomponents/index.jsx
+++ b/src/menu/components/tabs/tabcomponents/index.jsx
@@ -96,6 +96,7 @@
         search: '鎼滅储',
         table: '琛ㄦ牸',
         group: '鍒嗙粍',
+        editor: '瀵屾枃鏈�',
         card: '鍗$墖'
       }
       let i = 1
diff --git a/src/menu/datasource/index.jsx b/src/menu/datasource/index.jsx
index 9244b6b..1869282 100644
--- a/src/menu/datasource/index.jsx
+++ b/src/menu/datasource/index.jsx
@@ -115,7 +115,7 @@
 
     return (
       <div className="model-datasource">
-        <Icon type="setting" onClick={() => this.editDataSource()} />
+        <Icon type="setting" title="鏁版嵁婧�" onClick={() => this.editDataSource()} />
         <Modal
           wrapClassName="popview-modal"
           title={'鏁版嵁婧愰厤缃�'}
diff --git a/src/menu/menushell/card.jsx b/src/menu/menushell/card.jsx
index 3d365e8..fd43cac 100644
--- a/src/menu/menushell/card.jsx
+++ b/src/menu/menushell/card.jsx
@@ -13,6 +13,7 @@
 const TableCard = asyncComponent(() => import('@/menu/components/card/table-card'))
 const NormalTable = asyncComponent(() => import('@/menu/components/table/normal-table'))
 const NormalGroup = asyncComponent(() => import('@/menu/components/group/normal-group'))
+const BraftEditor = asyncComponent(() => import('@/menu/components/editor/braft-editor'))
 
 const Card = ({ id, card, moveCard, findCard, delCard, updateConfig }) => {
   const originalIndex = findCard(id).index
@@ -66,6 +67,8 @@
       return (<NormalTable card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'group' && card.subtype === 'normalgroup') {
       return (<NormalGroup group={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'editor') {
+      return (<BraftEditor card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     }
   }
   return (
diff --git a/src/menu/menushell/index.jsx b/src/menu/menushell/index.jsx
index ecbc6cf..9c2b767 100644
--- a/src/menu/menushell/index.jsx
+++ b/src/menu/menushell/index.jsx
@@ -89,6 +89,7 @@
         search: '鎼滅储',
         table: '琛ㄦ牸',
         group: '鍒嗙粍',
+        editor: '瀵屾枃鏈�',
         card: '鍗$墖'
       }
       let i = 1
diff --git a/src/menu/modelsource/option.jsx b/src/menu/modelsource/option.jsx
index 7a55036..d263619 100644
--- a/src/menu/modelsource/option.jsx
+++ b/src/menu/modelsource/option.jsx
@@ -9,6 +9,7 @@
 import TableCard from '@/assets/mobimg/table-card.png'
 import NormalTable from '@/assets/mobimg/normal-table.png'
 import Pie from '@/assets/mobimg/pie.png'
+import Editor from '@/assets/mobimg/editor.png'
 import Pie1 from '@/assets/mobimg/ring.png'
 import Pie2 from '@/assets/mobimg/nightingale.png'
 import Mainsearch from '@/assets/mobimg/mainsearch.png'
@@ -27,6 +28,7 @@
   { type: 'menu', url: bar1, component: 'bar', subtype: 'bar1', title: '鏉″舰鍥�', width: 24 },
   { type: 'menu', url: Pie, component: 'pie', subtype: 'pie', title: '楗煎浘', width: 12 },
   { type: 'menu', url: Pie1, component: 'pie', subtype: 'ring', title: '鐜浘', width: 12 },
+  { type: 'menu', url: Editor, component: 'editor', subtype: 'brafteditor', title: '瀵屾枃鏈�', width: 24 },
   { type: 'menu', url: Pie2, component: 'pie', subtype: 'nightingale', title: '鍗椾竵鏍煎皵鍥�', width: 12 },
   { type: 'menu', url: group, component: 'group', subtype: 'normalgroup', title: '鍒嗙粍', width: 24, forbid: ['billPrint'] },
 ]
diff --git a/src/menu/popview/index.jsx b/src/menu/popview/index.jsx
index 97061ff..2e937c9 100644
--- a/src/menu/popview/index.jsx
+++ b/src/menu/popview/index.jsx
@@ -474,7 +474,7 @@
 
     config.components.forEach(item => {
       if (error) return
-      if (item.subtype === 'propcard' && item.wrap.datatype === 'static') return
+      if ((item.subtype === 'propcard' || item.subtype === 'brafteditor') && item.wrap.datatype === 'static') return
 
       if (item.setting) {
         if (item.setting.interType === 'system' && item.setting.execute !== 'false' && !item.setting.dataresource) {
diff --git a/src/tabviews/custom/components/card/data-card/asyncButtonComponent.jsx b/src/tabviews/custom/components/card/data-card/asyncButtonComponent.jsx
deleted file mode 100644
index 5fb9c1a..0000000
--- a/src/tabviews/custom/components/card/data-card/asyncButtonComponent.jsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import React, {Component} from 'react'
-import { Button } from 'antd'
-
-/**
- * @description 寮傛鍔犺浇妯″潡
- * @param {*} importComponent
- */
-export default function asyncComponent(importComponent) {
-  return class extends Component {
-    constructor(props) {
-      super(props)
-
-      this.state = {
-        component: null
-      }
-    }
-
-    async componentDidMount() {
-      const {default: component} = await importComponent()
-
-      this.setState({component})
-    }
-
-    // <Button className="loading-skeleton" disabled={true}></Button> // 楠ㄦ灦鎸夐挳
-    render() {
-      const C = this.state.component
-      const btn = this.props.btn || {}
-
-      return C ?
-        <C {...this.props} /> :
-        <Button icon={btn.OpenType === 'excelOut' ? 'download' : 'upload'} disabled={true} title={btn.label} style={{border: 0, background: 'transparent'}}></Button>
-    }
-  }
-}
\ No newline at end of file
diff --git a/src/tabviews/custom/components/card/prop-card/asyncButtonComponent.jsx b/src/tabviews/custom/components/card/prop-card/asyncButtonComponent.jsx
deleted file mode 100644
index 5fb9c1a..0000000
--- a/src/tabviews/custom/components/card/prop-card/asyncButtonComponent.jsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import React, {Component} from 'react'
-import { Button } from 'antd'
-
-/**
- * @description 寮傛鍔犺浇妯″潡
- * @param {*} importComponent
- */
-export default function asyncComponent(importComponent) {
-  return class extends Component {
-    constructor(props) {
-      super(props)
-
-      this.state = {
-        component: null
-      }
-    }
-
-    async componentDidMount() {
-      const {default: component} = await importComponent()
-
-      this.setState({component})
-    }
-
-    // <Button className="loading-skeleton" disabled={true}></Button> // 楠ㄦ灦鎸夐挳
-    render() {
-      const C = this.state.component
-      const btn = this.props.btn || {}
-
-      return C ?
-        <C {...this.props} /> :
-        <Button icon={btn.OpenType === 'excelOut' ? 'download' : 'upload'} disabled={true} title={btn.label} style={{border: 0, background: 'transparent'}}></Button>
-    }
-  }
-}
\ No newline at end of file
diff --git a/src/tabviews/custom/components/card/table-card/asyncButtonComponent.jsx b/src/tabviews/custom/components/card/table-card/asyncButtonComponent.jsx
deleted file mode 100644
index 5fb9c1a..0000000
--- a/src/tabviews/custom/components/card/table-card/asyncButtonComponent.jsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import React, {Component} from 'react'
-import { Button } from 'antd'
-
-/**
- * @description 寮傛鍔犺浇妯″潡
- * @param {*} importComponent
- */
-export default function asyncComponent(importComponent) {
-  return class extends Component {
-    constructor(props) {
-      super(props)
-
-      this.state = {
-        component: null
-      }
-    }
-
-    async componentDidMount() {
-      const {default: component} = await importComponent()
-
-      this.setState({component})
-    }
-
-    // <Button className="loading-skeleton" disabled={true}></Button> // 楠ㄦ灦鎸夐挳
-    render() {
-      const C = this.state.component
-      const btn = this.props.btn || {}
-
-      return C ?
-        <C {...this.props} /> :
-        <Button icon={btn.OpenType === 'excelOut' ? 'download' : 'upload'} disabled={true} title={btn.label} style={{border: 0, background: 'transparent'}}></Button>
-    }
-  }
-}
\ No newline at end of file
diff --git a/src/tabviews/custom/components/editor/braft-editor/index.jsx b/src/tabviews/custom/components/editor/braft-editor/index.jsx
new file mode 100644
index 0000000..bacb134
--- /dev/null
+++ b/src/tabviews/custom/components/editor/braft-editor/index.jsx
@@ -0,0 +1,196 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Spin, notification } from 'antd'
+
+import asyncComponent from '@/utils/asyncComponent'
+import Api from '@/api'
+import UtilsDM from '@/utils/utils-datamanage.js'
+import MKEmitter from '@/utils/events.js'
+import './index.scss'
+
+const BraftContent = asyncComponent(() => import('@/tabviews/custom/components/share/braftContent'))
+const NormalHeader = asyncComponent(() => import('@/tabviews/custom/components/share/normalheader'))
+
+class BraftEditorContent extends Component {
+  static propTpyes = {
+    BID: PropTypes.any,              // 鐖剁骇Id
+    data: PropTypes.array,           // 缁熶竴鏌ヨ鏁版嵁
+    config: PropTypes.object,        // 缁勪欢閰嶇疆淇℃伅
+    mainSearch: PropTypes.any,       // 澶栧眰鎼滅储鏉′欢
+    menuType: PropTypes.any,         // 鑿滃崟绫诲瀷
+  }
+
+  state = {
+    BID: '',                   // 涓婄骇ID
+    config: null,              // 鍥捐〃閰嶇疆淇℃伅
+    loading: false,            // 鏁版嵁鍔犺浇鐘舵��
+    sync: false,               // 鏄惁缁熶竴璇锋眰鏁版嵁
+    data: {}                   // 鏁版嵁
+  }
+
+  UNSAFE_componentWillMount () {
+    const { data, initdata, BID } = this.props
+    let _config = fromJS(this.props.config).toJS()
+
+    let _data = {}
+    let _sync = false
+    
+    if (_config.setting && _config.wrap.datatype !== 'static') {
+      _sync = _config.setting.sync === 'true'
+
+      if (_sync && data) {
+        _data = data[_config.dataName] || {}
+        if (_data && Array.isArray(_data)) {
+          _data = _data[0] || {}
+        }
+        _sync = false
+      } else if (_sync && initdata) {
+        _data = initdata || {}
+        if (_data && Array.isArray(_data)) {
+          _data = _data[0] || {}
+        }
+        _sync = false
+      }
+    } else {
+      _data = {}
+    }
+
+    this.setState({
+      sync: _sync,
+      data: _data,
+      BID: BID || '',
+      config: _config,
+      arr_field: _config.columns.map(col => col.field).join(','),
+    }, () => {
+      if (_config.wrap.datatype !== 'static' && _config.setting && _config.setting.sync !== 'true' && _config.setting.onload === 'true') {
+        this.loadData()
+      }
+    })
+  }
+
+  componentDidMount () {
+    MKEmitter.addListener('reloadData', this.reloadData)
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('reloadData', this.reloadData)
+  }
+
+  /**
+   * @description 鍥捐〃鏁版嵁鏇存柊锛屽埛鏂板唴瀹�
+   */
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    const { sync, config } = this.state
+
+    if (sync && !is(fromJS(this.props.data), fromJS(nextProps.data))) {
+      let _data = {}
+      if (nextProps.data && nextProps.data[config.dataName]) {
+        _data = nextProps.data[config.dataName]
+        if (_data && Array.isArray(_data)) {
+          _data = _data[0]
+        }
+      }
+
+      this.setState({sync: false, data: _data})
+    } else if (nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
+      if (config.wrap.datatype !== 'static' && config.setting.syncRefresh === 'true') {
+        this.setState({}, () => {
+          this.loadData()
+        })
+      }
+    }
+  }
+
+  reloadData = (menuId) => {
+    const { config } = this.state
+
+    if (menuId !== config.uuid) return
+
+    this.loadData()
+  }
+
+  async loadData () {
+    const { mainSearch, menuType } = this.props
+    const { config, arr_field, BID } = this.state
+
+    if (config.wrap.datatype === 'static') {
+      this.setState({
+        data: {},
+        loading: false
+      })
+      return
+    } else if (config.setting.supModule && !BID) { // BID 涓嶅瓨鍦ㄦ椂锛屼笉鍋氭煡璇�
+      this.setState({
+        data: {},
+        loading: false
+      })
+      return
+    }
+
+    let searches = []
+    if (mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
+      let keys = searches.map(item => item.key)
+      mainSearch.forEach(item => {
+        if (!keys.includes(item.key)) {
+          searches.push(item)
+        }
+      })
+    }
+
+    this.setState({
+      loading: true
+    })
+
+    let _orderBy = config.setting.order || ''
+    let param = UtilsDM.getQueryDataParams(config.setting, arr_field, searches, _orderBy, 1, 1, BID, menuType)
+
+    let result = await Api.genericInterface(param)
+    if (result.status) {
+      let _data = result.data && result.data[0] ? result.data[0] : {}
+
+      this.setState({
+        data: _data,
+        loading: false
+      })
+    } else {
+      this.setState({
+        loading: false
+      })
+      notification.error({
+        top: 92,
+        message: result.message,
+        duration: 10
+      })
+    }
+  }
+
+  render() {
+    const { config, loading, data } = this.state
+
+    return (
+      <div className="custom-braft-editor-box" style={{...config.style}}>
+        {loading ?
+          <div className="loading-mask">
+            <div className="ant-spin-blur"></div>
+            <Spin />
+          </div> : null
+        }
+        <NormalHeader config={config}/>
+        <BraftContent
+          value={config.wrap.datatype !== 'static' ? (data[config.wrap.field] || '') : config.html}
+          encryption={config.wrap.datatype !== 'static' ? config.wrap.encryption : 'false'}
+        />
+      </div>
+    )
+  }
+}
+
+export default BraftEditorContent
\ No newline at end of file
diff --git a/src/tabviews/custom/components/editor/braft-editor/index.scss b/src/tabviews/custom/components/editor/braft-editor/index.scss
new file mode 100644
index 0000000..067a060
--- /dev/null
+++ b/src/tabviews/custom/components/editor/braft-editor/index.scss
@@ -0,0 +1,76 @@
+.custom-braft-editor-box {
+  background: #ffffff;
+  background-position: center center;
+  background-repeat: no-repeat;
+  background-size: cover;
+  min-height: 20px;
+  position: relative;
+
+  .card-row-list::after {
+    content: ' ';
+    display: block;
+    clear: both;
+  }
+
+  .card-row-list {
+    .card-item-box {
+      background-color: #ffffff;
+      transition: all 0.3s;
+    }
+    >.active >.card-item-box {
+      border-color: #1890ff!important;
+      box-shadow: 0 0 4px #1890ff;
+    }
+  }
+  .card-row-list.radio, .card-row-list.checkbox {
+    >.ant-col:not(.active):not(.selected):hover {
+      >.card-item-box {
+        border-color: #69c0ff!important;
+        box-shadow: 0 0 4px #69c0ff!important;
+      }
+    }
+  }
+  .card-row-list.true {
+    >.ant-col:hover {
+      >.card-item-box {
+        z-index: 1;
+        transform: scale(1.05);
+      }
+    }
+  }
+
+  .card-item-box {
+    position: relative;
+    background-position: center center;
+    background-repeat: no-repeat;
+    background-size: cover;
+    transition: all 0.3s;
+  }
+
+  .loading-mask {
+    position: absolute;
+    left: 40px;
+    top: 0;
+    right: 40px;
+    bottom: 0px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    text-align: justify;
+    z-index: 1;
+
+    .ant-spin-blur {
+      position: absolute;
+      width: 100%;
+      height: 100%;
+      opacity: 0.5;
+      background: #ffffff;
+    }
+  }
+}
+
+.custom-braft-editor-box::after {
+  content: ' ';
+  display: block;
+  clear: both;
+}
diff --git a/src/tabviews/custom/components/group/normal-group/index.jsx b/src/tabviews/custom/components/group/normal-group/index.jsx
index f38e4a2..356cebf 100644
--- a/src/tabviews/custom/components/group/normal-group/index.jsx
+++ b/src/tabviews/custom/components/group/normal-group/index.jsx
@@ -18,6 +18,7 @@
 const DataCard = asyncComponent(() => import('@/tabviews/custom/components/card/data-card'))
 const TableCard = asyncComponent(() => import('@/tabviews/custom/components/card/table-card'))
 const PropCard = asyncComponent(() => import('@/tabviews/custom/components/card/prop-card'))
+const BraftEditor = asyncComponent(() => import('@/tabviews/custom/components/editor/braft-editor'))
 
 class TabTransfer extends Component {
   static propTpyes = {
@@ -45,7 +46,7 @@
       if (item.type === 'tabs') return
 
       if (!item.setting || item.setting.interType !== 'system') return
-      if (!item.format || (item.subtype === 'propcard' && item.wrap.datatype === 'static')) return
+      if (!item.format) return
 
       if (item.dataName && (!item.pageable || (item.pageable && !item.setting.laypage)) && item.setting.onload === 'true' && item.setting.sync === 'true') {
         let param = this.getDefaultParam(item, _mainSearch)
@@ -267,6 +268,12 @@
             <TableCard config={item} data={data} BID={_bid} mainSearch={mainSearch} menuType={menuType} />
           </Col>
         )
+      } else if (item.type === 'editor') {
+        return (
+          <Col span={item.width} key={item.uuid}>
+            <BraftEditor config={item} data={data} BID={_bid} mainSearch={mainSearch} menuType={menuType} />
+          </Col>
+        )
       } else {
         return null
       }
diff --git a/src/tabviews/custom/components/share/braftContent/index.jsx b/src/tabviews/custom/components/share/braftContent/index.jsx
new file mode 100644
index 0000000..ccf8cc9
--- /dev/null
+++ b/src/tabviews/custom/components/share/braftContent/index.jsx
@@ -0,0 +1,58 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+
+import './index.scss'
+
+class BraftContent extends Component {
+  static propTpyes = {
+    value: PropTypes.any,       // 鍐呭
+    encryption: PropTypes.any,  // 鏄惁瑙g爜
+  }
+
+  state = {
+    html: ''
+  }
+
+  UNSAFE_componentWillMount () {
+    const { encryption, value } = this.props
+    let html = value
+
+    if (encryption === 'true' && html) {
+      try {
+        html = window.decodeURIComponent(window.atob(html))
+      } catch {
+        html = value
+      }
+    }
+    
+    this.setState({html})
+  }
+
+  UNSAFE_componentWillReceiveProps(nextProps) {
+    if (!is(fromJS(this.props), fromJS(nextProps))) {
+      const { encryption, value } = nextProps
+      let html = value
+
+      if (encryption === 'true' && html) {
+        try {
+          html = window.decodeURIComponent(window.atob(html))
+        } catch {
+          html = value
+        }
+      }
+      
+      this.setState({html})
+    }
+  }
+
+  render() {
+    const { html } = this.state
+    return (
+      <div className="braft-content" dangerouslySetInnerHTML={{ __html: html }}></div>
+    )
+  }
+}
+
+
+export default BraftContent
\ No newline at end of file
diff --git a/src/tabviews/custom/components/share/braftContent/index.scss b/src/tabviews/custom/components/share/braftContent/index.scss
new file mode 100644
index 0000000..ee9d422
--- /dev/null
+++ b/src/tabviews/custom/components/share/braftContent/index.scss
@@ -0,0 +1,25 @@
+.braft-content {
+  .media-wrap {
+    max-width: 100%;
+  }
+  img {
+    max-width: 100%;
+  }
+  video {
+    max-width: 100%;
+  }
+  table {
+    width: 100%;
+    border-collapse: collapse;
+    border-spacing: 0;
+    margin: 10px 0px;
+    tr:first-child {
+      background-color: #f0f0f0;
+    }
+    td, th {
+      padding: 5px 14px;
+      font-size: 16px;
+      border: 1px solid #ddd;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/tabviews/custom/components/share/tabtransfer/index.jsx b/src/tabviews/custom/components/share/tabtransfer/index.jsx
index 7e584ff..884813b 100644
--- a/src/tabviews/custom/components/share/tabtransfer/index.jsx
+++ b/src/tabviews/custom/components/share/tabtransfer/index.jsx
@@ -21,6 +21,7 @@
 const TableCard = asyncComponent(() => import('@/tabviews/custom/components/card/table-card'))
 const PropCard = asyncComponent(() => import('@/tabviews/custom/components/card/prop-card'))
 const NormalGroup = asyncComponent(() => import('@/tabviews/custom/components/group/normal-group'))
+const BraftEditor = asyncComponent(() => import('@/tabviews/custom/components/editor/braft-editor'))
 
 class TabTransfer extends Component {
   static propTpyes = {
@@ -58,7 +59,7 @@
       if (item.type === 'tabs' || item.type === 'group') return
 
       if (!item.setting || item.setting.interType !== 'system') return
-      if (!item.format || (item.subtype === 'propcard' && item.wrap.datatype === 'static')) return
+      if (!item.format) return
 
       if (item.dataName && (!item.pageable || (item.pageable && !item.setting.laypage)) && item.setting.onload === 'true' && item.setting.sync === 'true') {
         let param = this.getDefaultParam(item, _mainSearch)
@@ -304,6 +305,12 @@
             <NormalGroup config={item} bids={bids} mainSearch={mainSearch} menuType={menuType} />
           </Col>
         )
+      } else if (item.type === 'editor') {
+        return (
+          <Col span={item.width} key={item.uuid}>
+            <BraftEditor config={item} data={data} BID={BID} mainSearch={mainSearch} menuType={menuType} />
+          </Col>
+        )
       } else {
         return null
       }
diff --git a/src/tabviews/custom/index.jsx b/src/tabviews/custom/index.jsx
index ac068c0..3670784 100644
--- a/src/tabviews/custom/index.jsx
+++ b/src/tabviews/custom/index.jsx
@@ -26,6 +26,7 @@
 const MainSearch = asyncComponent(() => import('@/tabviews/zshare/topSearch'))
 const NormalTable = asyncComponent(() => import('./components/table/normal-table'))
 const NormalGroup = asyncComponent(() => import('./components/group/normal-group'))
+const BraftEditor = asyncComponent(() => import('./components/editor/braft-editor'))
 const SettingComponent = asyncComponent(() => import('@/tabviews/zshare/settingcomponent'))
 const PagemsgComponent = asyncComponent(() => import('@/tabviews/zshare/pageMessage'))
 
@@ -482,8 +483,12 @@
         return component
       }
 
+      if ((component.subtype === 'propcard' || component.subtype === 'brafteditor') && component.wrap.datatype === 'static') {
+        component.format = ''
+      }
+
       if (!component.setting) return component // 涓嶄娇鐢ㄧ郴缁熷嚱鏁版椂
-      if (!component.format || (component.subtype === 'propcard' && component.wrap.datatype === 'static')) return component // 娌℃湁鍔ㄦ�佹暟鎹�  鏁版嵁鏍煎紡 array 鎴� object
+      if (!component.format) return component  // 娌℃湁鍔ㄦ�佹暟鎹�  鏁版嵁鏍煎紡 array 鎴� object
       if (component.setting.interType !== 'system') { // 涓嶄娇鐢ㄧ郴缁熷嚱鏁版椂
         component.setting.sync = 'false'
         component.setting.laypage = component.setting.laypage === 'true'
@@ -822,6 +827,12 @@
             <NormalGroup config={item} BID={_bid} mainSearch={mainSearch} menuType={menuType} />
           </Col>
         )
+      } else if (item.type === 'editor') {
+        return (
+          <Col span={item.width} key={item.uuid}>
+            <BraftEditor config={item} data={data} BID={_bid} mainSearch={mainSearch} menuType={menuType} />
+          </Col>
+        )
       } else {
         return null
       }
diff --git a/src/views/billprint/index.jsx b/src/views/billprint/index.jsx
index 56f813f..bd4f620 100644
--- a/src/views/billprint/index.jsx
+++ b/src/views/billprint/index.jsx
@@ -21,6 +21,7 @@
 const PropCard = asyncComponent(() => import('@/tabviews/custom/components/card/prop-card'))
 const TableCard = asyncComponent(() => import('@/tabviews/custom/components/card/table-card'))
 const NormalTable = asyncComponent(() => import('@/tabviews/custom/components/table/normal-table'))
+const BraftEditor = asyncComponent(() => import('@/tabviews/custom/components/editor/braft-editor'))
 
 class BillPrint extends Component {
   state = {
@@ -153,9 +154,13 @@
           if (component.action) component.action = []
           if (component.search) component.search = []
           component.data = [] // 鍒濆鍖栨暟鎹负绌�
+
+          if ((component.subtype === 'propcard' || component.subtype === 'brafteditor') && component.wrap.datatype === 'static') {
+            component.format = ''
+          }
     
           if (!component.setting) return component // 涓嶄娇鐢ㄧ郴缁熷嚱鏁版椂
-          if (!component.format || (component.subtype === 'propcard' && component.wrap.datatype === 'static')) return component // 娌℃湁鍔ㄦ�佹暟鎹�  鏁版嵁鏍煎紡 array 鎴� object
+          if (!component.format) return component  // 娌℃湁鍔ㄦ�佹暟鎹�  鏁版嵁鏍煎紡 array 鎴� object
           if (component.setting.interType !== 'system') { // 涓嶄娇鐢ㄧ郴缁熷嚱鏁版椂
             component.setting.sync = 'false'
             return component
@@ -350,7 +355,7 @@
       let _results = results.filter(Boolean)
 
       let comps = components.map(item => {
-        if (item.subtype === 'propcard' && item.wrap.datatype === 'static') return item
+        if (!item.format) return item
 
         _results.forEach(res => {
           if (res.componentId === item.uuid && res.data) {
@@ -566,6 +571,12 @@
             <NormalTable config={item} initdata={item.data} mainSearch={[]} menuType="" />
           </Col>
         )
+      } else if (item.type === 'editor') {
+        return (
+          <Col span={item.width} key={item.uuid}>
+            <BraftEditor config={item} initdata={item.data} mainSearch={[]} menuType="" />
+          </Col>
+        )
       } else {
         return null
       }
diff --git a/src/views/menudesign/index.jsx b/src/views/menudesign/index.jsx
index b09c3fb..0958c06 100644
--- a/src/views/menudesign/index.jsx
+++ b/src/views/menudesign/index.jsx
@@ -769,7 +769,7 @@
 
     config.components.forEach(item => {
       if (error) return
-      if (item.subtype === 'propcard' && item.wrap.datatype === 'static') return
+      if ((item.subtype === 'propcard' || item.subtype === 'brafteditor') && item.wrap.datatype === 'static') return
 
       if (item.setting) {
         if (item.setting.interType === 'system' && item.setting.execute !== 'false' && !item.setting.dataresource) {

--
Gitblit v1.8.0