king
2024-08-25 326aa6b3effaccc71cfe0775d47b0f29eb3695a6
src/templates/sharecomponent/cardcomponent/index.jsx
@@ -1,15 +1,15 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Icon, Modal } from 'antd'
import { Modal, Popover } from 'antd'
import { EditOutlined, CloseOutlined, PlusOutlined } from '@ant-design/icons'
import Utils from '@/utils/utils.js'
import zhCN from '@/locales/zh-CN/model.js'
import enUS from '@/locales/en-US/model.js'
import { getCardDetailForm } from '@/templates/zshare/formconfig'
import { getCardDetailForm } from './formconfig'
import MkIcon from '@/components/mk-icon'
import DragDetail from './dragdetail'
import CardDetailForm from './carddetailform'
import avatar from '@/assets/img/avatar.png'
import './index.scss'
const { confirm } = Modal
@@ -22,22 +22,31 @@
  }
  state = {
    dict: (!localStorage.getItem('lang') || localStorage.getItem('lang') === 'zh-CN') ? zhCN : enUS,
    visible: false,
    modaltype: '',
    formlist: null,
    cardwidth: 0,
    cardheight: 0,
    cardcell: null   // 卡片元素
  }
  componentDidMount () {
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
  }
  UNSAFE_componentWillReceiveProps (nextProps) {
    if (!is(fromJS(this.props.card), fromJS(nextProps.card))) {
      setTimeout(() => {
        if (nextProps.card.extraAction && this.cardRef) {
          if (this.cardRef.offsetWidth !== this.state.cardwidth || this.cardRef.offsetHeight !== this.state.cardheight) {
            this.setState({
              cardwidth: this.cardRef.offsetWidth,
              cardheight: this.cardRef.offsetHeight
            })
          }
        }
      }, 200)
    }
  }
  plotChange = (values) => {
    const { card, config } = this.props
@@ -62,11 +71,15 @@
    const { config } = this.props
    if (!_cell) {
      _cell = {
        datatype: 'dynamic'
        datatype: 'dynamic',
        elemType: 'detail',
        width: 100,
        fontWeight: 'normal',
        fontSize: 14
      }
    }
    let _columns = config.columns.filter(col => ['text', 'number'].includes(col.type))
    let _columns = config.columns.filter(col => ['text', 'number', 'link', 'textarea'].includes(col.type))
    _columns = _columns.map(col => {
      return {
        uuid: col.uuid,
@@ -81,121 +94,363 @@
    this.setState({
      cardcell: _cell,
      visible: true,
      formlist: getCardDetailForm(_cell, _columns)
      modaltype: 'detail',
      formlist: getCardDetailForm(_cell, _columns, 'detail')
    })
  }
  editHeader = () => {
    const { config, card } = this.props
    let _columns = config.columns.filter(col => ['text', 'number'].includes(col.type))
    _columns = _columns.map(col => {
      return {
        uuid: col.uuid,
        value: col.field,
        text: col.label
      }
    })
    let _actions = config.action.filter(item =>
      (item.Ot && item.Ot !== 'notRequired' && !['excelIn', 'excelOut'].includes(item.OpenType)) ||
      item.funcType === 'changeuser'
    )
    let actionIds = []
    _actions = _actions.map(item => {
      actionIds.push(item.uuid)
      return {
        value: item.uuid,
        icon: item.icon,
        text: item.label
      }
    })
    let _cell = fromJS(card.header).toJS()
    if (_columns.filter(col => col.value === _cell.field).length === 0) {
      _cell.field = ''
    }
    if (_cell.actions.length > 0) {
      _cell.actions = _cell.actions.filter(item => actionIds.includes(item.value))
    }
    this.setState({
      cardcell: _cell,
      modaltype: 'header',
      formlist: getCardDetailForm(_cell, _columns, 'header', _actions)
    })
  }
  editBottom = () => {
    const { config, card } = this.props
    let _actions = config.action.filter(item =>
      (item.Ot && item.Ot !== 'notRequired' && !['excelIn', 'excelOut'].includes(item.OpenType)) ||
      item.funcType === 'changeuser'
    )
    let actionIds = []
    _actions = _actions.map(item => {
      actionIds.push(item.uuid)
      return {
        value: item.uuid,
        icon: item.icon,
        text: item.label
      }
    })
    let _cell = fromJS(card.bottom).toJS()
    if (_cell.actions.length > 0) {
      _cell.actions = _cell.actions.filter(item => actionIds.includes(item.value))
    }
    this.setState({
      cardcell: _cell,
      modaltype: 'bottom',
      formlist: getCardDetailForm(_cell, [], 'bottom', _actions)
    })
  }
  editAvatar = () => {
    const { config, card } = this.props
    let _columns = []
    config.columns.forEach(col => {
      if (['picture'].includes(col.type)) {
        _columns.push({
          type: 'picture',
          uuid: col.uuid,
          value: col.field,
          text: col.label
        })
      } else if (['text', 'number'].includes(col.type) && col.marks) {
        let mark = col.marks.filter(_mark => _mark.signType === 'icon' && _mark.icon)[0]
        if (mark) {
          _columns.push({
            type: 'icon',
            uuid: col.uuid,
            value: col.field,
            text: col.label,
            icon: mark.icon,
            color: mark.color[1]
          })
        }
      }
    })
    let _cell = fromJS(card.avatar).toJS()
    if (_columns.filter(col => col.value === _cell.field && col.type === _cell.type).length === 0) {
      _cell.field = ''
      _cell.content = ''
    }
    this.setState({
      cardcell: _cell,
      modaltype: 'avatar',
      formlist: getCardDetailForm(_cell, _columns, 'avatar', [])
    })
  }
  handleSubmit = () => {
    const { card } = this.props
    let _details = fromJS(card.details).toJS()
    const { modaltype } = this.state
    this.detailFormRef.handleConfirm().then(res => {
      if (!res.uuid) {
        res.uuid = Utils.getuuid()
        _details.push(res)
      } else {
        _details = _details.map(item => {
          if (item.uuid === res.uuid) return res
          return item
    this.cardFormRef.handleConfirm().then(res => {
      if (modaltype === 'detail') {
        let _details = fromJS(this.props.card.details).toJS()
        if (!res.uuid) {
          res.uuid = Utils.getuuid()
          _details.push(res)
        } else {
          _details = _details.map(item => {
            if (item.uuid === res.uuid) return res
            return item
          })
        }
        this.setState({
          cardcell: null,
          modaltype: '',
          formlist: null
        })
        this.plotChange({details: _details})
      } else if (modaltype === 'header') {
        this.setState({
          cardcell: null,
          modaltype: '',
          formlist: null
        })
        this.plotChange({header: res})
      } else if (modaltype === 'bottom') {
        this.setState({
          cardcell: null,
          modaltype: '',
          formlist: null
        })
        this.plotChange({bottom: res})
      } else if (modaltype === 'avatar') {
        this.setState({
          cardcell: null,
          modaltype: '',
          formlist: null
        })
        this.plotChange({avatar: res})
      }
      this.setState({
        cardcell: null,
        visible: false,
        formlist: null
      })
      this.plotChange({details: _details})
    })
  }
  editModalCancel = () => {
    this.setState({
      cardcell: null,
      visible: false,
      modaltype: '',
      formlist: null
    })
  }
  deletedetail = (cell) => {
    const { card } = this.props
    const { dict } = this.state
    let _this = this
    let that = this
    confirm({
      content: dict['model.confirm'] + dict['model.delete'] + ` - ${cell.content} ?`,
      okText: dict['model.confirm'],
      cancelText: dict['header.cancel'],
      content: `确定删除 - ${cell.content} ?`,
      onOk() {
        let _details = fromJS(card.details).toJS()
        _details = _details.filter(item => item.uuid !== cell.uuid)
        _this.plotChange({details: _details})
        that.plotChange({details: _details})
      },
      onCancel() {}
    })
  }
  deleteElem = (type) => {
    let that = this
    confirm({
      content: '确定删除?',
      onOk() {
        let _subelement = fromJS(that.props.card.subelement).toJS()
        _subelement = _subelement.filter(_type => _type !== type)
        that.plotChange({subelement: _subelement})
      },
      onCancel() {}
    })
  }
  componentDidMount() {
    const { card } = this.props
    if (card.extraAction && this.cardRef) {
      this.setState({
        cardwidth: this.cardRef.offsetWidth,
        cardheight: this.cardRef.offsetHeight
      })
    }
  }
  componentDidUpdate() {
    const { card } = this.props
    if (card.extraAction && this.cardRef) {
      if (this.cardRef.offsetWidth !== this.state.cardwidth || this.cardRef.offsetHeight !== this.state.cardheight) {
        this.setState({
          cardwidth: this.cardRef.offsetWidth,
          cardheight: this.cardRef.offsetHeight
        })
      }
    }
  }
  render() {
    const { card } = this.props
    const { dict, visible, cardcell } = this.state
    const { modaltype, cardcell, cardwidth, cardheight } = this.state
    let _width = '100%'
    if (card.bottom && card.bottom.actions.length > 0) {
      _width = Math.floor((100 / card.bottom.actions.length) * 10000) / 10000 + '%'
    }
    if (card.widthType === 'absolute') {
      card.cardWidth = 6
    }
    if (card.avatar && card.avatar.widthType === 'absolute') {
      card.avatar.width = 32
    }
    let outclass = 'ant-col-' + card.cardWidth
    if (card.background) {
      outclass += ' background ' + card.background
    }
    if (card.border === 'hidden') {
      outclass += ' without-border'
    } else {
      outclass += ' ant-card-bordered'
    }
    let metastyle = {}
    if (card.subelement.includes('avatar')) {
      // 计算卡片宽度
      let _outWidth = document.body.offsetWidth - 260
      let _cardWidth = Math.floor(_outWidth * card.cardWidth / 24 - 20)
      if (card.avatar.type === 'picture') {
        if (card.avatar.width < 90 && card.avatar.display !== 'block') {
          metastyle.display = 'flex'
        }
      } else {
        if (card.avatar.size < _cardWidth * 0.9 && card.avatar.display !== 'block') {
          metastyle.display = 'flex'
        }
      }
    }
    return (
      <div className="line-card-edit-box">
      <div className="line-card-edit-box mingke-table">
        {card.title ? <p className="chart-title">{card.title}</p> : null}
        <div
          className={'ant-card ant-card-bordered chart-card' + (card.widthType === 'ratio' ? ' ant-col ant-col-' + card.cardWidth : '')}
          style={card.widthType === 'absolute' ? { width: card.cardWidth } : null}
          ref={(ref) => this.cardRef = ref}
          className={'ant-card chart-card ant-col ' + outclass}
        >
          <div className="ant-card-head">
            <div className="ant-card-head-wrapper">
              <div className="ant-card-head-title">Card Title</div>
              <div className="ant-card-extra">
                <span>Action</span>
          {card.subelement.includes('header') ?
            <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
              <div className="mk-popover-control">
                <EditOutlined className="edit" onClick={this.editHeader} />
                <CloseOutlined className="close" onClick={() => this.deleteElem('header')} />
              </div>
            } trigger="hover">
              <div className="ant-card-head">
                <div className="ant-card-head-wrapper">
                  <div className="ant-card-head-title">{card.header.content}</div>
                  {card.header.actions && card.header.actions.length > 0 ?
                    <div className="ant-card-extra">
                      <span>
                        {['icon', 'all'].includes(card.header.show) ? <MkIcon type={card.header.actions[0].icon || 'dash'}/> : null}
                        {['text', 'all'].includes(card.header.show) ? card.header.actions[0].text : null}
                      </span>
                    </div> : null
                  }
                </div>
              </div>
            </Popover> : null
          }
          <div className="ant-card-body">
            <div className="ant-card-meta" style={metastyle}>
              <PlusOutlined onClick={() => this.editdetail()} />
              {card.subelement.includes('avatar') ?
                <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
                  <div className="mk-popover-control">
                    <EditOutlined className="edit" onClick={this.editAvatar} />
                    <CloseOutlined className="close" onClick={() => this.deleteElem('avatar')} />
                  </div>
                } trigger="hover">
                  <div className="ant-card-meta-avatar" style={card.avatar.type === 'icon' ? {width: card.avatar.width, paddingTop: card.avatar.width} : {width: card.avatar.width + '%', paddingTop: card.avatar.width + '%'}}>
                    <span className="ant-avatar ant-avatar-circle ant-avatar-image" style={{borderRadius: card.avatar.radius === 'true' ? '50%' : 0}}>
                      {card.avatar.type === 'picture' ? <img src={avatar} alt=""/> : null}
                      {card.avatar.type === 'icon' ? <MkIcon className={'font ' + card.avatar.color} style={{fontSize: card.avatar.size + 'px'}} type={card.avatar.icon} /> : null}
                    </span>
                  </div>
                </Popover> : null
              }
              <div className="ant-card-meta-detail" style={metastyle.display ? {flex: 1} : null}>
                <DragDetail
                  cardObj={card}
                  handleList={this.handleList}
                  handleMenu={this.editdetail}
                  deleteMenu={this.deletedetail}
                />
              </div>
            </div>
          </div>
          <div className="ant-card-body">
            <div className="ant-card-meta">
              <Icon type="plus" onClick={() => this.editdetail()} />
              {card.cardType === 'card2' ? <div className="ant-card-meta-avatar">
                <span className="ant-avatar ant-avatar-circle ant-avatar-image" style={{width: 32, height: 32}}>
                  <img src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" alt=""/>
                </span>
              </div> : null }
              <DragDetail
                list={card.details}
                handleList={this.handleList}
                handleMenu={this.editdetail}
                deleteMenu={this.deletedetail}
              />
            </div>
          </div>
          {card.cardType === 'card2' ? <ul className="ant-card-actions">
            <li style={{width: '33.3333%'}}>
              <span>
                <Icon type="setting"/>
              </span>
            </li>
            <li style={{width: '33.3333%'}}>
              <span>
                <Icon type="edit"/>
              </span>
            </li>
            <li style={{width: '33.3333%'}}>
              <span>
                <Icon type="edit"/>
              </span>
            </li>
          </ul> : null}
          {card.subelement.includes('bottom') ?
            <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
              <div className="mk-popover-control">
                <EditOutlined className="edit" onClick={this.editBottom} />
                <CloseOutlined className="close" onClick={() => this.deleteElem('bottom')} />
              </div>
            } trigger="hover">
              <ul className="ant-card-actions">
                {card.bottom.actions.map((item, i) => (<li key={i} style={{width: _width}}>
                  <span>
                    {['icon', 'all'].includes(card.bottom.show) ? <MkIcon type={item.icon || 'dash'}/> : null}
                    {['text', 'all'].includes(card.bottom.show) ? item.text : null}
                  </span>
                </li>))}
              </ul>
            </Popover> : null
          }
        </div>
        {card.extraAction ?
          <div className={'ant-card chart-card chart-card-insert ' + outclass} style={{ width: cardwidth, height: cardheight }} >
            <PlusOutlined style={cardwidth > cardheight ? {fontSize: cardheight / 2 + 'px', lineHeight: cardheight + 'px'} : {fontSize: cardwidth / 2 + 'px', lineHeight: cardheight + 'px'}} />
          </div> : null
        }
        {/* 显示列编辑 */}
        <Modal
          title="编辑"
          visible={visible}
          visible={!!modaltype}
          width={650}
          maskClosable={false}
          onOk={this.handleSubmit}
@@ -203,11 +458,10 @@
          destroyOnClose
        >
          <CardDetailForm
            dict={dict}
            card={cardcell}
            inputSubmit={this.handleSubmit}
            formlist={this.state.formlist}
            wrappedComponentRef={(inst) => this.detailFormRef = inst}
            wrappedComponentRef={(inst) => this.cardFormRef = inst}
          />
        </Modal>
      </div>