king
2021-04-08 9a60da3f80eacbaadb98b6c9697aeffcc8affe57
2021-04-08
9个文件已修改
8个文件已添加
791 ■■■■■ 已修改文件
src/assets/mobimg/login.png 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/dragaction/card.jsx 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/formconfig.jsx 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columns/editColumn/formconfig.jsx 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/stylecontroller/index.jsx 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/components/login/normal-login/index.jsx 149 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/components/login/normal-login/index.scss 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/components/login/normal-login/loginform.jsx 130 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/components/login/wrapsetting/index.jsx 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/components/login/wrapsetting/index.scss 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/components/login/wrapsetting/settingform/index.jsx 253 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/components/login/wrapsetting/settingform/index.scss 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/menushell/card.jsx 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/menushell/index.jsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/modulesource/option.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/cardcellList/index.jsx 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/share/normalTable/index.jsx 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mobimg/login.png
src/menu/components/card/cardcellcomponent/dragaction/card.jsx
@@ -18,6 +18,11 @@
const QrCode = asyncComponent(() => import('@/components/qrcode'))
const Video = asyncComponent(() => import('@/components/video'))
const MarkColumn = asyncIconComponent(() => import('@/menu/components/share/markcomponent'))
const PicRadio = {
  '4:3': '75%', '3:2': '66.67%', '16:9': '56.25%', '2:1': '50%', '3:1': '33.33%', '4:1': '25%',
  '5:1': '20%', '6:1': '16.67%', '7:1': '14.29%', '8:1': '12.5%', '9:1': '11.11%',
  '10:1': '10%', '3:4': '133.33%', '2:3': '150%', '9:16': '177.78%'
}
const Card = ({ id, parent, fields, card, moveCard, findCard, editCard, delCard, copyCard, changeStyle, updateMarks, doubleClickCard }) => {
  const originalIndex = findCard(id).index
@@ -85,12 +90,8 @@
        _imagestyle.borderRadius = card.style.borderRadius
      }
      if (card.lenWidRadio === '16:9') {
        _imagestyle.paddingTop = '56.25%'
      } else if (card.lenWidRadio === '3:2') {
        _imagestyle.paddingTop = '66.67%'
      } else if (card.lenWidRadio === '4:3') {
        _imagestyle.paddingTop = '75%'
      if (PicRadio[card.lenWidRadio]) {
        _imagestyle.paddingTop = PicRadio[card.lenWidRadio]
      } else {
        _imagestyle.paddingTop = '100%'
      }
src/menu/components/card/cardcellcomponent/formconfig.jsx
@@ -293,9 +293,21 @@
      required: true,
      options: [
        { value: '1:1', text: '1:1' },
        { value: '3:2', text: '3:2' },
        { value: '4:3', text: '4:3' },
        { value: '16:9', text: '16:9' }
        { value: '3:2', text: '3:2' },
        { value: '16:9', text: '16:9' },
        { value: '2:1', text: '2:1' },
        { value: '3:1', text: '3:1' },
        { value: '4:1', text: '4:1' },
        { value: '5:1', text: '5:1' },
        { value: '6:1', text: '6:1' },
        { value: '7:1', text: '7:1' },
        { value: '8:1', text: '8:1' },
        { value: '9:1', text: '9:1' },
        { value: '10:1', text: '10:1' },
        { value: '3:4', text: '3:4' },
        { value: '2:3', text: '2:3' },
        { value: '9:16', text: '9:16' },
      ]
    },
    {
src/menu/components/table/normal-table/columns/editColumn/formconfig.jsx
@@ -255,9 +255,21 @@
      required: true,
      options: [
        { value: '1:1', text: '1:1' },
        { value: '3:2', text: '3:2' },
        { value: '4:3', text: '4:3' },
        { value: '16:9', text: '16:9' }
        { value: '3:2', text: '3:2' },
        { value: '16:9', text: '16:9' },
        { value: '2:1', text: '2:1' },
        { value: '3:1', text: '3:1' },
        { value: '4:1', text: '4:1' },
        { value: '5:1', text: '5:1' },
        { value: '6:1', text: '6:1' },
        { value: '7:1', text: '7:1' },
        { value: '8:1', text: '8:1' },
        { value: '9:1', text: '9:1' },
        { value: '10:1', text: '10:1' },
        { value: '3:4', text: '3:4' },
        { value: '2:3', text: '2:3' },
        { value: '9:16', text: '9:16' },
      ]
    },
    {
src/menu/stylecontroller/index.jsx
@@ -329,7 +329,7 @@
                    label={<Icon title="宽度" type="column-width" />}
                    labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                  >
                    <StyleInput defaultValue={card.width || ''} options={['px', 'vh', 'vw']} onChange={this.changeWidth}/>
                    <StyleInput defaultValue={card.width || ''} options={['px', 'vh', 'vw', '%']} onChange={this.changeWidth}/>
                  </Form.Item>
                </Col>
              </Panel> : null}
@@ -557,7 +557,7 @@
                    label={<Icon title="上边距" type="arrow-up"/>}
                    labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                  >
                    <StyleInput defaultValue={card.marginTop || '0px'} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'marginTop')}/>
                    <StyleInput defaultValue={card.marginTop || '0px'} options={['px', 'vh', 'vw', '%']} onChange={(val) => this.changeNormalStyle(val, 'marginTop')}/>
                  </Form.Item>
                </Col>
                <Col span={24}>
@@ -566,7 +566,7 @@
                    label={<Icon title="下边距" type="arrow-down"/>}
                    labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                  >
                    <StyleInput defaultValue={card.marginBottom || '0px'} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'marginBottom')}/>
                    <StyleInput defaultValue={card.marginBottom || '0px'} options={['px', 'vh', 'vw', '%']} onChange={(val) => this.changeNormalStyle(val, 'marginBottom')}/>
                  </Form.Item>
                </Col>
                <Col span={24}>
@@ -575,7 +575,7 @@
                    label={<Icon title="左边距" type="arrow-left"/>}
                    labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                  >
                    <StyleInput defaultValue={card.marginLeft || '0px'} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'marginLeft')}/>
                    <StyleInput defaultValue={card.marginLeft || '0px'} options={['px', 'vh', 'vw', '%']} onChange={(val) => this.changeNormalStyle(val, 'marginLeft')}/>
                  </Form.Item>
                </Col>
                <Col span={24}>
@@ -584,7 +584,7 @@
                    label={<Icon title="右边距" type="arrow-right"/>}
                    labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                  >
                    <StyleInput defaultValue={card.marginRight || '0px'} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'marginRight')}/>
                    <StyleInput defaultValue={card.marginRight || '0px'} options={['px', 'vh', 'vw', '%']} onChange={(val) => this.changeNormalStyle(val, 'marginRight')}/>
                  </Form.Item>
                </Col>
              </Panel> : null}
@@ -595,7 +595,7 @@
                    label={<Icon title="上边距" type="arrow-up"/>}
                    labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                  >
                    <StyleInput defaultValue={card.paddingTop || '0px'} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'paddingTop')}/>
                    <StyleInput defaultValue={card.paddingTop || '0px'} options={['px', 'vh', 'vw', '%']} onChange={(val) => this.changeNormalStyle(val, 'paddingTop')}/>
                  </Form.Item>
                </Col>
                <Col span={24}>
@@ -604,7 +604,7 @@
                    label={<Icon title="下边距" type="arrow-down"/>}
                    labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                  >
                    <StyleInput defaultValue={card.paddingBottom || '0px'} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'paddingBottom')}/>
                    <StyleInput defaultValue={card.paddingBottom || '0px'} options={['px', 'vh', 'vw', '%']} onChange={(val) => this.changeNormalStyle(val, 'paddingBottom')}/>
                  </Form.Item>
                </Col>
                <Col span={24}>
@@ -613,7 +613,7 @@
                    label={<Icon title="左边距" type="arrow-left"/>}
                    labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                  >
                    <StyleInput defaultValue={card.paddingLeft || '0px'} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'paddingLeft')}/>
                    <StyleInput defaultValue={card.paddingLeft || '0px'} options={['px', 'vh', 'vw', '%']} onChange={(val) => this.changeNormalStyle(val, 'paddingLeft')}/>
                  </Form.Item>
                </Col>
                <Col span={24}>
@@ -622,7 +622,7 @@
                    label={<Icon title="右边距" type="arrow-right"/>}
                    labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                  >
                    <StyleInput defaultValue={card.paddingRight || '0px'} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'paddingRight')}/>
                    <StyleInput defaultValue={card.paddingRight || '0px'} options={['px', 'vh', 'vw', '%']} onChange={(val) => this.changeNormalStyle(val, 'paddingRight')}/>
                  </Form.Item>
                </Col>
              </Panel> : null}
src/pc/components/login/normal-login/index.jsx
New file
@@ -0,0 +1,149 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Icon, Popover } from 'antd'
import asyncIconComponent from '@/utils/asyncIconComponent'
import asyncComponent from '@/utils/asyncComponent'
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 LoginForm = asyncComponent(() => import('./loginform'))
const WrapComponent = asyncIconComponent(() => import('../wrapsetting'))
class PropCardEditComponent extends Component {
  static propTpyes = {
    card: PropTypes.object,
    deletecomponent: PropTypes.func,
    updateConfig: PropTypes.func,
  }
  state = {
    dict: sessionStorage.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 || '',
        width: card.width || 24,
        name: card.name,
        subtype: card.subtype,
        wrap: { name: card.name, width: card.width || 24, title: '', switch: 'false', datatype: 'static' },
        style: { background: '#ffffff', width: '330px', borderRadius: '4px', marginLeft: '55vw' },
        loginWays: [
          {type: 'uname_pwd', label: '账号密码', remember: 'true', disabled: false, labelStyle: {}, submitStyle: {}, submitLabel: '登录'},
          {type: 'sms_vcode', label: '短信验证码', disabled: true, labelStyle: {}, submitStyle: {}, submitLabel: '登录'}
        ]
      }
      if (card.config) {
        let config = fromJS(card.config).toJS()
        _card.wrap = config.wrap
        _card.wrap.name = card.name
        _card.style = config.style
      }
      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))
  }
  /**
   * @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], ['width', 'background', 'border', 'padding', 'margin'], card.style)
  }
  getStyle = (comIds, style) => {
    const { card } = this.state
    if (comIds.length !== 1 || comIds[0] !== card.uuid) return
    let _card = {...card, style}
    this.setState({
      card: _card
    })
    this.props.updateConfig(_card)
  }
  clickComponent = (e) => {
    if (sessionStorage.getItem('style-control') === 'true' || sessionStorage.getItem('style-control') === 'component') {
      e.stopPropagation()
      MKEmitter.emit('clickComponent', this.state.card)
    }
  }
  render() {
    const { card, dict } = this.state
    return (
      <div className="login-edit-box" style={{...card.style}} onClick={this.clickComponent} id={card.uuid}>
        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
          <div className="mk-popover-control">
            <WrapComponent config={card} updateConfig={this.updateComponent} />
            <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" />
            <Icon className="close" title="删除组件" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
          </div>
        } trigger="hover">
          <Icon type="tool" />
        </Popover>
        <LoginForm loginWays={card.loginWays} dict={dict} />
      </div>
    )
  }
}
export default PropCardEditComponent
src/pc/components/login/normal-login/index.scss
New file
@@ -0,0 +1,58 @@
.login-edit-box {
  position: relative;
  box-sizing: border-box;
  background: #ffffff;
  background-position: center center;
  background-repeat: no-repeat;
  background-size: cover;
  min-height: 100px;
  .card-control {
    position: absolute;
    top: 0px;
    left: 0px;
    .anticon-tool {
      right: auto;
      left: 1px;
      padding: 1px;
    }
  }
  .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);
  }
  .login-edit-form {
    .ant-form-item {
      font-size: 16px;
      margin: 0 15px 15px;
      .ant-input {
        height: 35px;
      }
    }
    button:not(.vercode) {
      width: 100%;
      height: 40px;
      line-height: 1;
      font-size: 18px;
      margin-bottom: 25px;
    }
    .ant-form-item:last-child {
      margin-bottom: 0;
    }
  }
}
.login-edit-box::after {
  display: block;
  content: ' ';
  clear: both;
}
.login-edit-box:hover {
  z-index: 1;
  box-shadow: 0px 0px 4px #1890ff;
}
src/pc/components/login/normal-login/loginform.jsx
New file
@@ -0,0 +1,130 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Form, Icon, Input, Button, Checkbox, Tabs } from 'antd'
import './index.scss'
const { TabPane } = Tabs
class LoginTabForm extends Component {
  static propTpyes = {
    dict: PropTypes.object,
    loginWays: PropTypes.array,
  }
  state = {
    activeKey: 'uname_pwd',
    username: '',
    password: '',
    loginWays: [],
    smsId: '',
    verdisabled: false
  }
  UNSAFE_componentWillMount () {
    const { loginWays } = this.props
    let smsId = ''
    let _loginWays = []
    loginWays.forEach(item => {
      if (item.type === 'sms_vcode') {
        smsId = item.smsId
        _loginWays.push(item)
      } else if (item.type === 'uname_pwd') {
        _loginWays.push(item)
      }
    })
    this.setState({
      smsId: smsId,
      loginWays: _loginWays,
      activeKey: _loginWays[0].type,
    })
  }
  UNSAFE_componentWillReceiveProps (nextProps) {
    if (!is(fromJS(this.props.loginWays), fromJS(nextProps.loginWays))) {
      let smsId = ''
      let _loginWays = []
      nextProps.loginWays.forEach(item => {
        if (item.type === 'sms_vcode') {
          smsId = item.smsId
          _loginWays.push(item)
        } else if (item.type === 'uname_pwd') {
          _loginWays.push(item)
        }
      })
      this.setState({
        smsId: smsId,
        loginWays: _loginWays,
        activeKey: _loginWays[0].type
      })
    }
  }
  onChangeTab = (activeKey) => {
    this.setState({activeKey})
  }
  /**
   * @description 组件销毁,清除state更新
   */
  componentWillUnmount () {
    this.setState = () => {
      return
    }
  }
  render() {
    const { activeKey, verdisabled, loginWays } = this.state
    return (
      <Form className="login-edit-form">
        <Tabs type="card" activeKey={activeKey} onChange={this.onChangeTab}>
          {loginWays.map(item => (<TabPane tab={item.label} key={item.type}></TabPane>))}
        </Tabs>
        <div className="form-item-wrap">
          {activeKey === 'uname_pwd' ? <Form.Item>
            <Input
              prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />}
              placeholder="用户名"
              autoComplete="off"
            />
          </Form.Item> : null}
          {activeKey === 'uname_pwd' ? <Form.Item>
            <Input.Password placeholder="密码" prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />} />
          </Form.Item> : null}
          {activeKey === 'sms_vcode' ? <Form.Item>
            <Input
              placeholder="手机号"
              autoComplete="off"
            />
          </Form.Item> : null}
          {activeKey === 'sms_vcode' ? <Form.Item>
            <Input
              addonAfter={
                <Button type="link" className="vercode" size="small" disabled={verdisabled}>
                  获取验证码
                </Button>
              }
              placeholder="验证码"
              autoComplete="off"
            />
          </Form.Item> : null}
          {activeKey === 'uname_pwd' ? <Form.Item className="minline">
            <Checkbox>记住密码</Checkbox>
          </Form.Item> : null}
          {['uname_pwd', 'sms_vcode'].includes(activeKey) ? <Form.Item className="btn-login">
            <Button type="primary" htmlType="submit" className="login-form-button">
              登录
            </Button>
          </Form.Item> : null}
        </div>
      </Form>
    )
  }
}
export default LoginTabForm
src/pc/components/login/wrapsetting/index.jsx
New file
@@ -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: sessionStorage.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" title="编辑" onClick={() => this.editDataSource()} />
        <Modal
          wrapClassName="popview-modal"
          title={config.type === 'table' ? '表格设置' : '卡片设置'}
          visible={visible}
          width={800}
          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
src/pc/components/login/wrapsetting/index.scss
New file
@@ -0,0 +1,7 @@
.model-menu-setting-wrap {
  display: inline-block;
  >.anticon-edit {
    color: #1890ff;
  }
}
src/pc/components/login/wrapsetting/settingform/index.jsx
New file
@@ -0,0 +1,253 @@
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: []
  }
  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()
    }
  }
  render() {
    const { wrap, config } = this.props
    const { getFieldDecorator } = this.props.form
    const { roleList } = 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>
            {config.subtype === 'propcard' ? <Col span={12}>
              <Form.Item label={
                <Tooltip placement="topLeft" title="选择静态值,无需配置数据源。">
                  <Icon type="question-circle" />
                  数据来源
                </Tooltip>
              }>
                {getFieldDecorator('datatype', {
                  initialValue: wrap.datatype || 'dynamic'
                })(
                  <Radio.Group>
                    <Radio value="dynamic">动态</Radio>
                    <Radio value="static">静态</Radio>
                  </Radio.Group>
                )}
              </Form.Item>
            </Col> : null}
            {config.subtype === 'datacard' ? <Col span={12}>
              <Form.Item label={
                <Tooltip placement="topLeft" title="数据源中选择分页时有效。">
                  <Icon type="question-circle" />
                  分页风格
                </Tooltip>
              }>
                {getFieldDecorator('pagestyle', {
                  initialValue: wrap.pagestyle || 'page'
                })(
                  <Radio.Group>
                    <Radio value="page">页码</Radio>
                    <Radio value="switch">左右切换</Radio>
                  </Radio.Group>
                )}
              </Form.Item>
            </Col> : null}
            {config.subtype !== 'tablecard' ? <Col span={12}>
              <Form.Item label="卡片属性">
                {getFieldDecorator('cardType', {
                  initialValue: wrap.cardType || ''
                })(
                  <Radio.Group style={{whiteSpace: 'nowrap'}}>
                    <Radio key="" value=""> 不可选 </Radio>
                    <Radio key="radio" value={'radio'}> 单选 </Radio>
                    {config.subtype !== 'propcard' ? <Radio key="checkbox" value={'checkbox'}> 多选 </Radio> : null}
                  </Radio.Group>
                )}
              </Form.Item>
            </Col> : null}
            {config.subtype !== 'tablecard' ? <Col span={12}>
              <Form.Item label={
                <Tooltip placement="topLeft" title="设置为居中对齐或右对齐,只在卡片为1行时有效。">
                  <Icon type="question-circle" />
                  卡片排列
                </Tooltip>
              }>
                {getFieldDecorator('cardFloat', {
                  initialValue: wrap.cardFloat || 'left'
                })(
                  <Radio.Group style={{whiteSpace: 'nowrap'}}>
                    <Radio key="left" value="left"> 左对齐 </Radio>
                    <Radio key="center" value="center"> 居中 </Radio>
                    <Radio key="right" value="right"> 右对齐 </Radio>
                  </Radio.Group>
                )}
              </Form.Item>
            </Col> : null}
            {config.subtype !== 'tablecard' ? <Col span={12}>
              <Form.Item label={
                <Tooltip placement="topLeft" title="鼠标悬浮于卡片上方时,卡片放大1.05倍。">
                  <Icon type="question-circle" />
                  卡片放大
                </Tooltip>
              }>
                {getFieldDecorator('scale', {
                  initialValue: wrap.scale || 'false'
                })(
                  <Radio.Group>
                    <Radio key="false" value="false"> 否 </Radio>
                    <Radio key="true" value="true"> 是 </Radio>
                  </Radio.Group>
                )}
              </Form.Item>
            </Col> : null}
            {config.subtype === 'tablecard' ? <Col span={12}>
              <Form.Item label={
                <Tooltip placement="topLeft" title="表格高度,超出时滚动,高度为空时根据内容自适应。">
                  <Icon type="question-circle" />
                  高度
                </Tooltip>
              }>
                {getFieldDecorator('height', {
                  initialValue: wrap.height
                })(<InputNumber min={100} max={2000} precision={0} onPressEnter={this.handleSubmit} />)}
              </Form.Item>
            </Col> : null}
            {config.subtype === 'propcard' ? <Col span={12}>
              <Form.Item label={
                <Tooltip placement="topLeft" title="选择类型为《页眉/页脚》时,打印的每页里都会带有该组件。">
                  <Icon type="question-circle" />
                  组件类型
                </Tooltip>
              }>
                {getFieldDecorator('printType', {
                  initialValue: wrap.printType || 'content'
                })(
                  <Radio.Group>
                    <Radio value="content">内容</Radio>
                    <Radio value="headerOrfooter">页眉/页脚</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)
src/pc/components/login/wrapsetting/settingform/index.scss
New file
@@ -0,0 +1,11 @@
.model-menu-setting-form {
  position: relative;
  .anticon-question-circle {
    color: #c49f47;
    margin-right: 3px;
  }
  .ant-input-number {
    width: 100%;
  }
}
src/pc/menushell/card.jsx
@@ -17,6 +17,7 @@
const BraftEditor = asyncComponent(() => import('@/menu/components/editor/braft-editor'))
const CodeSandbox = asyncComponent(() => import('@/menu/components/code/sandbox'))
const NormalNavbar = asyncComponent(() => import('@/pc/components/navbar/normal-navbar'))
const NormalLogin = asyncComponent(() => import('@/pc/components/login/normal-login'))
const CarouselDataCard = asyncComponent(() => import('@/menu/components/carousel/data-card'))
const CarouselPropCard = asyncComponent(() => import('@/menu/components/carousel/prop-card'))
@@ -88,6 +89,8 @@
      return (<BraftEditor card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'code') {
      return (<CodeSandbox card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'login') {
      return (<NormalLogin card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    }
  }
  return (
src/pc/menushell/index.jsx
@@ -49,7 +49,7 @@
    let uuids = MenuUtils.getDelButtonIds(card)
    confirm({
      title: `确定删除《${card.name}》吗?`,
      title: `确定删除${card.name ? `《${card.name}》` : '组件'}吗?`,
      content: hasComponent ? '当前组件中含有子组件!' : '',
      onOk() {
        MKEmitter.emit('delButtons', uuids)
@@ -102,7 +102,8 @@
        code: '自定义',
        navbar: '导航栏',
        carousel: '轮播',
        card: '卡片'
        card: '卡片',
        login: '登录'
      }
      let i = 1
      
src/pc/modulesource/option.jsx
@@ -18,6 +18,7 @@
import Carousel from '@/assets/mobimg/carousel.png'
import Carousel1 from '@/assets/mobimg/carousel1.png'
import form from '@/assets/mobimg/form.png'
import Login from '@/assets/mobimg/login.png'
// 组件配置信息
export const menuOptions = [
@@ -41,4 +42,5 @@
  { type: 'menu', url: SandBox, component: 'code', subtype: 'sandbox', 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 },
  { type: 'menu', url: Login, component: 'login', subtype: 'normallogin', title: '登录', width: 24 },
]
src/tabviews/custom/components/card/cardcellList/index.jsx
@@ -21,6 +21,11 @@
const BarCode = asyncElementComponent(() => import('@/components/barcode'))
const QrCode = asyncElementComponent(() => import('@/components/qrcode'))
const Video = asyncComponent(() => import('@/components/video'))
const PicRadio = {
  '4:3': '75%', '3:2': '66.67%', '16:9': '56.25%', '2:1': '50%', '3:1': '33.33%', '4:1': '25%',
  '5:1': '20%', '6:1': '16.67%', '7:1': '14.29%', '8:1': '12.5%', '9:1': '11.11%',
  '10:1': '10%', '3:4': '133.33%', '2:3': '150%', '9:16': '177.78%'
}
class CardCellComponent extends Component {
  static propTpyes = {
@@ -443,12 +448,8 @@
        _imagestyle.borderRadius = _style.borderRadius
      }
      if (card.lenWidRadio === '16:9') {
        _imagestyle.paddingTop = '56.25%'
      } else if (card.lenWidRadio === '3:2') {
        _imagestyle.paddingTop = '66.67%'
      } else if (card.lenWidRadio === '4:3') {
        _imagestyle.paddingTop = '75%'
      if (PicRadio[card.lenWidRadio]) {
        _imagestyle.paddingTop = PicRadio[card.lenWidRadio]
      } else {
        _imagestyle.paddingTop = '100%'
      }
src/tabviews/custom/components/share/normalTable/index.jsx
@@ -15,7 +15,11 @@
const { Paragraph } = Typography
const CardCellComponent = asyncComponent(() => import('@/tabviews/custom/components/card/cardcellList'))
const PicRadio = {
  '4:3': '75%', '3:2': '66.67%', '16:9': '56.25%', '2:1': '50%', '3:1': '33.33%', '4:1': '25%',
  '5:1': '20%', '6:1': '16.67%', '7:1': '14.29%', '8:1': '12.5%', '9:1': '11.11%',
  '10:1': '10%', '3:4': '133.33%', '2:3': '150%', '9:16': '177.78%'
}
class BodyRow extends React.Component {
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.props.data), fromJS(nextProps.data)) || !is(fromJS(this.props.className), fromJS(nextProps.className))
@@ -272,12 +276,8 @@
      let cols = 24 / (col.picSort || 1)
      let paddingTop = '100%'
      if (col.lenWidRadio === '16:9') {
        paddingTop = '56.25%'
      } else if (col.lenWidRadio === '3:2') {
        paddingTop = '66.67%'
      } else if (col.lenWidRadio === '4:3') {
        paddingTop = '75%'
      if (PicRadio[col.lenWidRadio]) {
        paddingTop = PicRadio[col.lenWidRadio]
      }
      resProps.children = (