king
2020-03-06 e2ac71fbc53b7119ae87c5a3b08cdcf830b497e2
2020-03-06
10个文件已修改
9个文件已添加
2个文件已删除
2891 ■■■■■ 已修改文件
src/api/index.js 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/barcode.jpg 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/qrcode.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/shunfeng.jpg 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/commontable/index.jsx 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/index.jsx 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/formtabconfig/index.jsx 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/index.jsx 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils.js 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/printTemplate/dragelement/card.jsx 158 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/printTemplate/dragelement/index.jsx 37 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/printTemplate/dragelement/index.scss 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/printTemplate/dragelement/itemtypes.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/printTemplate/fileupload/index.jsx 140 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/printTemplate/fileupload/index.scss 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/printTemplate/index.jsx 735 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/printTemplate/index.scss 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/printTemplate/mutilform/index.jsx 257 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/printTemplate/mutilform/index.scss 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/printTemplate/option.js 862 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/printTemplate/print.js 407 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/index.js
@@ -117,6 +117,43 @@
  }
  /**
   * @description 获取或修改云端配置
   */
  getCloudConfig (param) {
    param.lang = localStorage.getItem('lang') || ''
    param.appkey = window.GLOB.appkey || ''
    if (sessionStorage.getItem('CloudUserID') && options.cloudServiceApi) { // 存在云端登录信息,且存在云端地址
      param.rduri = options.cloudServiceApi
      param.userid = sessionStorage.getItem('CloudUserID')
      param.SessionUid = sessionStorage.getItem('CloudSessionUid') || ''
      param.LoginUID = sessionStorage.getItem('CloudLoginUID') || ''
    } else if (window.GLOB.mainSystemApi) {
      param.rduri = window.GLOB.mainSystemApi
      param.userid = sessionStorage.getItem('UserID')
      param.SessionUid = sessionStorage.getItem('SessionUid') || ''
      param.LoginUID = sessionStorage.getItem('LoginUID') || ''
    } else {
      param.userid = sessionStorage.getItem('UserID')
      param.SessionUid = sessionStorage.getItem('SessionUid') || ''
      param.LoginUID = sessionStorage.getItem('LoginUID') || ''
    }
    param.nonc = Utils.getuuid()
    let keys = Object.keys(param).sort()
    keys = keys.filter(key => key !== 'rduri')
    let values = keys.map(key => key + param[key]).join('')
    param.sign  = md5(values)
    param.t = new Date().getTime()
    return axios({
      url: '/webapi/dostars',
      data: param
    })
  }
  /**
   * @description 获取或修改系统配置,增加appkey
   */
  getSystemConfig (param) {
@@ -306,6 +343,57 @@
  }
  /**
   * @description 上传base64
   * @param {String} base64 base64图片编码
   */
  fileuploadbase64 (base64, service = 'local') {
    let param = {
      BasePath: 'Content/Upload',
      lang: localStorage.getItem('lang') || '',
      appkey: window.GLOB.appkey || '',
      Base64Img: base64
    }
    if (service === 'sso' && window.GLOB.mainSystemApi) {
      param.rduri = window.GLOB.mainSystemApi
      param.userid = sessionStorage.getItem('UserID')
      param.SessionUid = sessionStorage.getItem('SessionUid') || ''
      param.LoginUID = sessionStorage.getItem('LoginUID') || ''
    } else if (service === 'cloud' && options.cloudServiceApi) {
      param.rduri = options.cloudServiceApi
      param.userid = sessionStorage.getItem('CloudUserID')
      param.SessionUid = sessionStorage.getItem('CloudSessionUid') || ''
      param.LoginUID = sessionStorage.getItem('CloudLoginUID') || ''
    } else {
      param.userid = sessionStorage.getItem('UserID')
      param.SessionUid = sessionStorage.getItem('SessionUid') || ''
      param.LoginUID = sessionStorage.getItem('LoginUID') || ''
    }
    param.nonc = Utils.getuuid()
    let keys = Object.keys(param).sort()
    keys = keys.filter(key => key !== 'rduri')
    let values = keys.map(key => key + param[key]).join('')
    param.sign  = md5(values)
    param.t = new Date().getTime()
    if (param.rduri) {
      param.rduri = param.rduri.replace(/webapi(.*)$/, 'webapi/SaveBase64Image')
      return axios({
        url: '/webapi/dostars',
        data: param
      })
    } else {
      return axios({
        url: '/webapi/SaveBase64Image',
        data: param
      })
    }
  }
  /**
   * @description 文件上传
   */
  getFileUpload (param) {
src/assets/img/barcode.jpg
src/assets/img/qrcode.png
src/assets/img/shunfeng.jpg
src/tabviews/commontable/index.jsx
@@ -836,6 +836,16 @@
    this.loadconfig()
  }
  componentDidMount () {
    document.onkeydown = (event) => {
      let e = event || window.event
      if(e && e.keyCode === 27) {
        console.log(this.props.MenuID)
      }
    }
  }
  UNSAFE_componentWillReceiveProps(nextProps) {
    if (nextProps.refreshTab && nextProps.refreshTab.MenuID === this.props.MenuID) {
      if (nextProps.refreshTab.position === 'grid') {
src/templates/comtableconfig/index.jsx
@@ -171,10 +171,19 @@
      originMenu: JSON.parse(JSON.stringify(menu)),
      selectedTables: _config.tables || [],
      menuformlist: [
        // {
        //   type: 'select',
        //   key: 'firparentId',
        //   label: '一级菜单',
        //   initVal: menu.ParentID,
        //   required: true,
        //   readonly: false,
        //   options: this.props.supMenuList
        // },
        {
          type: 'select',
          key: 'parentId',
          label: this.state.dict['header.menu.supMenu'],
          label: '二级菜单',
          initVal: menu.ParentID,
          required: true,
          readonly: false,
@@ -1531,6 +1540,7 @@
  getFuncNames = (data, funcNames, tableNames) => {
    data.forEach(item => {
      console.log(item)
      if (item.subfuncs) {
        this.getFuncNames(item.subfuncs, funcNames, tableNames)
      } else {
@@ -1538,11 +1548,10 @@
          tableNames.push(item.tableName)
        }
        if (item.innerFunc) {
          // funcNames.push({func: item.innerFunc, label: item})
          funcNames.push(item.innerFunc)
        }
        // if (item.outerFunc) {
        //   funcNames.push(item.outerFunc)
        // }
        if (item.callbackFunc) {
          funcNames.push(item.callbackFunc)
        }
@@ -1788,7 +1797,7 @@
          Sort: (this.props.supMenuList.length + 1) * 10,
          PageParam: JSON.stringify(_pageParam),
          LongParam: _LongParam,
          LText: _funcs.map(item => `select '${menu.MenuID}' as MenuID,'${item}' as ProcName`),
          LText: _funcs.map(item => `select '${menu.MenuID}' as MenuID,'${item}' as ProcName,'${item}' as MenuName`),
          LTexttb: _tables.map(item => `select '${menu.MenuID}' as MenuID,'${item}' as tbName`)
        }
src/templates/formtabconfig/index.jsx
@@ -595,6 +595,7 @@
        }
        let _groups = null
        let fieldrepet = false // 字段重复
        if (card.iscopy) {
          _groups = config.groups.map(group => {
@@ -602,6 +603,10 @@
            group.sublist.forEach((item, index) => {
              if (item.uuid === card.originUuid) {
                _index = index
              }
              if (item.uuid !== res.uuid && item.field === res.field) {
                fieldrepet = true
              }
            })
@@ -617,6 +622,10 @@
        } else {
          _groups = config.groups.map(group => {
            group.sublist = group.sublist.map(item => {
              if (item.uuid !== res.uuid && item.field === res.field) {
                fieldrepet = true
              }
              if (item.uuid === res.uuid) {
                return res
              } else {
@@ -630,6 +639,15 @@
          })
        }
        if (fieldrepet) {
          notification.warning({
            top: 92,
            message: '字段名重复!',
            duration: 10
          })
          return
        }
        this.setState({
          config: {...config, groups: _groups},
          optionLibs: optionLibs,
src/templates/modalconfig/index.jsx
@@ -499,6 +499,8 @@
        })
      }
      let fieldrepet = false // 字段重复
      if (modalType === 'copy' && card.originUuid) {
        if (_config.groups.length > 0) {
          _config.groups = _config.groups.map(group => {
@@ -506,6 +508,10 @@
            group.sublist.forEach((item, index) => {
              if (item.uuid === card.originUuid) {
                _index = index
              }
              if (item.uuid !== res.uuid && item.field === res.field) {
                fieldrepet = true
              }
            })
@@ -521,6 +527,10 @@
            if (item.uuid === card.originUuid) {
              _index = index
            }
            if (item.uuid !== res.uuid && item.field === res.field) {
              fieldrepet = true
            }
          })
          _config.fields.splice(_index + 1, 0, res)
@@ -529,6 +539,10 @@
        if (_config.groups.length > 0) {
          _config.groups.forEach(group => {
            group.sublist = group.sublist.map(item => {
              if (item.uuid !== res.uuid && item.field === res.field) {
                fieldrepet = true
              }
              if (item.uuid === res.uuid) {
                return res
              } else {
@@ -538,6 +552,10 @@
          })
        } else {
          _config.fields = _config.fields.map(item => {
            if (item.uuid !== res.uuid && item.field === res.field) {
              fieldrepet = true
            }
            if (item.uuid === res.uuid) {
              return res
            } else {
@@ -546,6 +564,15 @@
          })
        }
      }
      if (fieldrepet) {
        notification.warning({
          top: 92,
          message: '字段名重复!',
          duration: 10
        })
        return
      }
      
      _config.fields = _config.fields.filter(item => !item.origin)
src/utils/utils.js
@@ -1,5 +1,6 @@
import moment from 'moment'
import md5 from 'md5'
import options from '@/store/options.js'
const service = window.GLOB.service ? (/\/$/.test(window.GLOB.service) ? window.GLOB.service : window.GLOB.service + '/') : ''
@@ -391,6 +392,7 @@
   */
  static getrealurl (url) {
    if (!url) return ''
    let baseurl = ''
    if (process.env.NODE_ENV === 'production') {
      baseurl = document.location.origin + '/' + service
@@ -405,6 +407,24 @@
  }
  /**
   * @description 获取云端图片真实路径
   * @return {String}    url 图片路径
   */
  static getcloudurl (url) {
    if (!url) return ''
    let baseurl = ''
    if (options.cloudServiceApi) {
      baseurl = options.cloudServiceApi.replace(/webapi(.*)$/, '')
    } else {
      baseurl = document.location.origin + '/' + service
    }
    return url.match(/^http/) || url.match(/^\/\//) ? url : baseurl + url
  }
  /**
   * @description 获取下拉搜索查询条件
   * @return {String} item   搜索条件信息
   */
src/views/printTemplate/dragelement/card.jsx
File was deleted
src/views/printTemplate/dragelement/index.jsx
@@ -1,44 +1,19 @@
import React, { useState } from 'react'
import React from 'react'
import { useDrop } from 'react-dnd'
import { is, fromJS } from 'immutable'
import update from 'immutability-helper'
import { Col, Icon } from 'antd'
import Utils from '@/utils/utils.js'
import Card from './card'
import ItemTypes from './itemtypes'
import './index.scss'
const Container = ({list, type }) => {
  const [cards, setCards] = useState(list)
  const moveCard = (id, atIndex) => {
    const { card, index } = findCard(id)
    const _cards = update(cards, { $splice: [[index, 1], [atIndex, 0, card]] })
    handleList(type, _cards)
  }
  if (!is(fromJS(cards), fromJS(list))) {
    setCards(list)
  }
  const findCard = id => {
    const card = cards.filter(c => `${c.uuid}` === id)[0]
    return {
      card,
      index: cards.indexOf(card),
    }
  }
const Container = ({dropcard}) => {
 
  const [, drop] = useDrop({
    accept: ItemTypes[type],
    accept: 'print',
    drop(item) {
      dropcard(item)
    }
  })
  return (
    <div ref={drop} className="ant-row">
    <div ref={drop} className="print-area">
      <canvas id="darea"></canvas>
    </div>
  )
}
src/views/printTemplate/dragelement/index.scss
@@ -11,3 +11,13 @@
    margin-left: 10px;
  }
}
.print-area {
  display: inline-block;
  margin: 0 auto;
  margin-right: 30px;
  canvas {
    box-shadow: 0px 0px 7px rgba(0, 0, 0, 0.2);
  }
}
src/views/printTemplate/dragelement/itemtypes.js
File was deleted
src/views/printTemplate/fileupload/index.jsx
New file
@@ -0,0 +1,140 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Upload, message, Button, Icon, Progress } from 'antd'
import Api from '@/api'
import './index.scss'
let service = window.GLOB.service ? (/\/$/.test(window.GLOB.service) ? window.GLOB.service : window.GLOB.service + '/') : ''
let Url = '/Upload'
if (process.env.NODE_ENV === 'production') {
  Url = document.location.origin + '/' + service + 'zh-CN/Home/Upload'
}
class FileUpload extends Component {
  static propTpyes = {
    value: PropTypes.array    // 按钮信息、表单列表
  }
  state = {
    baseUrl: Url,
    percent: 0,
    showprogress: false
  }
  init = async () => {
    try {
      const OSSData = await this.mockGetOSSData()
      this.setState({
        OSSData
      })
    } catch (error) {
      message.error(error)
    }
  }
  onChange = ({ fileList }) => {
    const { onChange } = this.props
    if (onChange) {
      onChange([...fileList])
    }
  }
  onRemove = file => {
    const { value, onChange } = this.props
    const files = value.filter(v => v.url !== file.url)
    if (onChange) {
      onChange(files)
    }
  }
  getExtraData = () => {
    return {
      RootPath: 'Content/images/upload/'
    }
  }
  shardupload = (file, shardSize, shardCount, i, fileList) => {
    let start = i * shardSize
    let end = Math.min(file.size, start + shardSize)
    let form = new FormData()
    form.append('file', file.slice(start, end)) //slice方法用于切出文件的一部分
    form.append('RootPath', 'Content/images/upload/')
    form.append('name', file.name)
    form.append('total', shardCount)
    form.append('index', i + 1)
    if (i < shardCount) {
      i++
      Api.getFileUpload(form).then(res => {
        if (res) {
          this.setState({
            percent: Math.floor(100 * (i / shardCount))
          })
          this.shardupload(file, shardSize, shardCount, i, fileList)
        }
      })
    } else {
      this.setState({
        percent: 100
      }, () => {
        setTimeout(() => {
          this.setState({
            showprogress: false,
            percent: 0
          })
        }, 200)
      })
    }
  }
  beforeUpload = (file, fileList) => {
    let shardSize = 2 * 1024 * 1024
    // let shardSize = 3 * 1024
    if (file.size > shardSize) {
      this.setState({
        showprogress: true,
        percent: 0
      })
      let shardCount = Math.ceil(file.size / shardSize)
      this.shardupload(file, shardSize, shardCount, 0, fileList)
      return false
    } else {
      return true
    }
  }
  render() {
    const { value } = this.props
    const { showprogress, percent, baseUrl } = this.state
    const props = {
      name: 'file',
      disabled: showprogress,
      fileList: value,
      action: baseUrl,
      method: 'post',
      multiple: true,
      // headers: {'RootPath': 'Content/images/upload/'},
      onChange: this.onChange,
      onRemove: this.onRemove,
      data: this.getExtraData,
      beforeUpload: this.beforeUpload,
    }
    return (
      <Upload {...props}>
        <Button>
          <Icon type="upload" /> 点击上传
        </Button>
        {showprogress ? <Progress percent={percent} size="small" /> : null}
      </Upload>
    )
  }
}
export default FileUpload
src/views/printTemplate/fileupload/index.scss
New file
@@ -0,0 +1,5 @@
.main-form-field .ant-progress-small.ant-progress-line {
  position: absolute;
  bottom: -20px;
  left: 0px;
}
src/views/printTemplate/index.jsx
@@ -1,43 +1,65 @@
import React, {Component} from 'react'
import { DndProvider } from 'react-dnd'
import { is, fromJS } from 'immutable'
import HTML5Backend from 'react-dnd-html5-backend'
import { Card } from 'antd'
import { Card, notification, Row, Button, Modal } from 'antd'
import DragElement from './dragelement'
import MutilForm from './mutilform'
import SourceElement from './dragelement/source'
import {
  printItems,
  originConfig,
  getpageform,
  getTextForm,
  getBarcodeForm,
  getQrcodeForm,
  getImageForm,
  getElement,
  barurl,
  qrurl,
  imgurl
} from './option.js'
import Utils from '@/utils/utils.js'
import printCtrl from './print.js'
import Api from '@/api'
import './index.scss'
const printItems = [
  {
    type: 'print',
    label: '文本',
    subType: 'text',
    icon: 'file-text'
  },
  {
    type: 'print',
    label: '条形码',
    subType: 'barcode',
    icon: 'barcode'
  },
  {
    type: 'print',
    label: '二维码',
    subType: 'qrcode',
    icon: 'qrcode'
  },
  {
    type: 'print',
    label: '图片',
    subType: 'picture',
    icon: 'file-image'
  }
]
const { confirm } = Modal
let dropPoint = null
let origin = null
let timer = null
let preorigin = null
let nextorigin = null
class PrintTemplate extends Component {
  state = {
    ID: null
    config: null,
    ID: null,
    editItemId: '',
    editItemType: '',
    fields: [],
    formlist: null,
    saveloading: false
  }
  componentDidMount () {
  getclickpoint = (e) => {
    const { config } = this.state
    let scrollTop = document.documentElement.scrollTop || document.body.scrollTop
    let screenX = e.clientX
    let screenY = e.clientY + scrollTop
    let offsetT = screenY - document.getElementById('darea').offsetTop
    let offsetL = screenX - document.getElementById('darea').offsetLeft
    let cx = Math.floor(offsetL / parseInt(document.getElementById('darea').style.width) * config.width)
    let cy = Math.floor(offsetT / parseInt(document.getElementById('darea').style.height) * config.height)
    return {
      cx: cx,
      cy: cy
    }
  }
  UNSAFE_componentWillMount () {
    let _param = window.atob(this.props.match.params.param)
    let _params = {}
    _param.split('&').forEach(cell => {
@@ -47,6 +69,632 @@
    this.setState({
      ID: _params.ID
    })
  }
  componentDidMount () {
    // 点击切换编辑元素
    document.getElementById('darea').addEventListener('click', (e) => {
      e.stopPropagation()
      let position = this.getclickpoint(e)
      let cx = position.cx
      let cy = position.cy
      let _selectItem = null
      let _config = JSON.parse(JSON.stringify(this.state.config))
      _config.elements.forEach(element => {
        let x = +element.left
        let y = +element.top
        let width = +element.width
        let height = +element.height
        let rotate = +element.rotate
        if (rotate === 90 || rotate === 270) {
          let _c = width
          x = x + width / 2 - height / 2
          y = y + height / 2 - width / 2
          width = height
          height = _c
        }
        if (width === 0) {
          x -= 4
          width = 8
        }
        if (height === 0) {
          y -= 4
          height = 8
        }
        if (cx > x && cx < x + width && cy > y && cy < y + height) {
          _selectItem = element
        }
      })
      if (!_selectItem) {
        _selectItem = _config
      } else {
        _config.elements = _config.elements.filter(ele => ele.uuid !== _selectItem.uuid)
        _config.elements.push(_selectItem)
      }
      let _formlist = null
      if (_selectItem.type === 'Template') {
        _formlist = getpageform(_selectItem)
      } else if (_selectItem.type === 'text') {
        _formlist = getTextForm(_selectItem, this.state.fields)
      } else if (_selectItem.type === 'barcode') {
        _formlist = getBarcodeForm(_selectItem, this.state.fields)
      } else if (_selectItem.type === 'qrcode') {
        _formlist = getQrcodeForm(_selectItem, this.state.fields)
      } else if (_selectItem.type === 'image') {
        _formlist = getImageForm(_selectItem, this.state.fields)
      }
      this.setState({
        config: _config,
        editItemId: _selectItem.uuid,
        editItemType: _selectItem.type,
        formlist: _formlist
      }, () => {
        this.resetview()
      })
    })
    // 触发拖动事件
    document.getElementById('darea').addEventListener('mousedown', (e) => {
      const { config } = this.state
      if (!this.state.editItemType || this.state.editItemType === 'Template') {
        origin = null
        return
      }
      let _selectItem = JSON.parse(JSON.stringify(this.state.config.elements.filter(ele => ele.uuid === this.state.editItemId)[0]))
      let _preItem = JSON.parse(JSON.stringify(_selectItem))
      let position = this.getclickpoint(e)
      let cx = position.cx
      let cy = position.cy
      let x = +_selectItem.left
      let y = +_selectItem.top
      let width = +_selectItem.width
      let height = +_selectItem.height
      let rotate = +_selectItem.rotate
      if (rotate === 90 || rotate === 270) {
        let _c = width
        x = x + width / 2 - height / 2
        y = y + height / 2 - width / 2
        width = height
        height = _c
      }
      if (width === 0) {
        x -= 4
        width = 8
      }
      if (height === 0) {
        y -= 4
        height = 8
      }
      if (cx > x && cx < x + width && cy > y && cy < y + height) {
        if (width > 3 && height > 3 && cx > x + width - 3 && cx < x + width + 2 && cy > y + height - 3 && cy < y + height + 2) {
          origin = {
            cx: cx,
            cy: cy,
            width: +_selectItem.width,
            height: +_selectItem.height
          }
          timer = setInterval(() => {
            if (JSON.stringify(preorigin) !== JSON.stringify(nextorigin)) {
              preorigin = nextorigin
              let _width = origin.width + (nextorigin.cx - origin.cx)
              let _height = origin.height + (nextorigin.cy - origin.cy)
              if (_width < 0) {
                _width = 0
              } else if (_selectItem.left + _width > config.width) {
                _width = config.width - _selectItem.left
              }
              if (_height < 0) {
                _height = 0
              } else if (_height + _selectItem.top > config.height) {
                _height = config.height - _selectItem.top
              }
              _selectItem.width = _width
              _selectItem.height = _height
              let result = this.resetItem(_selectItem)
              if (!is(fromJS(result), fromJS(_preItem))) {
                _preItem = JSON.parse(JSON.stringify(result))
                this.FormRef.resetForm(result)
                config.elements = config.elements.map(item => {
                  if (item.uuid === result.uuid) return result
                  return item
                })
                this.setState({
                  config: config
                }, () => {
                  this.resetview()
                })
              }
            }
          }, 100)
        } else {
          origin = {
            cx: cx,
            cy: cy,
            left: +_selectItem.left,
            top: +_selectItem.top
          }
          timer = setInterval(() => {
            if (JSON.stringify(preorigin) !== JSON.stringify(nextorigin)) {
              preorigin = nextorigin
              let _left = origin.left + (nextorigin.cx - origin.cx)
              let _top = origin.top + (nextorigin.cy - origin.cy)
              if (_left < 0) {
                _left = 0
              } else if (_left + _selectItem.width > config.width) {
                _left = config.width - _selectItem.width
              }
              if (_top < 0) {
                _top = 0
              } else if (_top + _selectItem.height > config.height) {
                _top = config.height - _selectItem.height
              }
              _selectItem.left = _left
              _selectItem.top = _top
              let result = this.resetItem(_selectItem)
              if (!is(fromJS(result), fromJS(_preItem))) {
                _preItem = JSON.parse(JSON.stringify(result))
                this.FormRef.resetForm(result)
                config.elements = config.elements.map(item => {
                  if (item.uuid === result.uuid) return result
                  return item
                })
                this.setState({
                  config: config
                }, () => {
                  this.resetview()
                })
              }
            }
          }, 100)
        }
      } else {
        origin = null
      }
    })
    document.getElementById('darea').addEventListener('mousemove', (e) => {
      if (!this.state.editItemType || this.state.editItemType === 'Template' || !origin) {
        return
      }
      let position = this.getclickpoint(e)
      nextorigin = {
        cx: position.cx,
        cy: position.cy
      }
    })
    document.getElementById('darea').addEventListener('mouseup', (e) => {
      origin = null
      clearInterval(timer)
    })
    document.getElementById('darea').addEventListener('mouseleave', (e) => {
      origin = null
      clearInterval(timer)
    })
    // 元素添加
    document.getElementById('darea').addEventListener('drop', (e) => {
      dropPoint = this.getclickpoint(e)
    })
    if (document.body.offsetWidth < 1360) {
      document.getElementById('darea').style.width = '600px'
    } else if (document.body.offsetWidth < 1500) {
      document.getElementById('darea').style.width = '700px'
    } else if (document.body.offsetWidth < 1920) {
      document.getElementById('darea').style.width = '800px'
    }
    this.loadconfig()
  }
  resetbox = () => {
    const { config } = this.state
    let ratio = (config.height || 1) / (config.width || 1)
    document.getElementById('darea').style.height = parseInt(document.getElementById('darea').style.width) * ratio + 'px'
    printCtrl.sketch(config, null)
  }
  resetview () {
    const { config, editItemId } = this.state
    printCtrl.sketch(config, editItemId)
  }
  /**
   * @description 获取模板配置信息
   */
  async loadconfig () {
    let param = {
      func: 's_PrintTemplateMGetData',
      ID: this.state.ID
    }
    let result = await Api.getCloudConfig(param)
    if (result.status) {
      let _config = ''
      if (result.ConfigParam) {
        try {
          _config = JSON.parse(window.decodeURIComponent(window.atob(result.ConfigParam)))
        } catch (e) {
          notification.warning({
            top: 92,
            message: '配置信息解析错误!',
            duration: 10
          })
          _config = ''
        }
      }
      if (!_config) {
        _config = originConfig
      }
      _config.name = result.PrintTempName || ''
      _config.remark = result.Remark || ''
      _config.PrintTempNO = result.PrintTempNO || ''
      _config.type = 'Template'
      _config.uuid = Utils.getuuid()
      if (result.data && result.data[0] && result.data[0].TableName) {
        this.loadFields(result.data[0].TableName)
      }
      this.setState({
        config: _config,
        editItemId: _config.uuid,
        editItemType: _config.type,
        formlist: getpageform(_config)
      }, () => {
        this.resetbox()
      })
    } else {
      notification.warning({
        top: 92,
        message: result.ErrMesg,
        duration: 10
      })
    }
  }
  /**
   * @description 获取可用字段
   */
  async loadFields (TBName) {
    let param = {
      func: 'sPC_Get_FieldName',
      TBName: TBName
    }
    let result = await Api.getCloudConfig(param)
    if (result.status) {
      let _fields = [{
        value: '',
        text: '空',
        type: ''
      }]
      let _f = new Map()
      result.FDName.forEach(item => {
        if (item.FieldName && !_f.has(item.FieldName)) {
          _f.set(item.FieldName, true)
          _fields.push({
            value: item.FieldName,
            text: item.FieldDec,
            type: item.FieldType
          })
        }
      })
      this.setState({
        fields: _fields
      })
    } else {
      notification.warning({
        top: 92,
        message: result.ErrMesg,
        duration: 10
      })
    }
  }
  dropcard = (item) => {
    const { config } = this.state
    let position = null
    if (dropPoint) {
      position = dropPoint
      dropPoint = null
    } else {
      return
    }
    let _width = Math.floor(config.width / 4)
    let _height = Math.floor(_width / 2)
    let _cx = Math.floor(position.cx - _width / 2)
    let _cy = Math.floor(position.cy - _height / 2)
    if (_cx < 0) { // 元素添加时,避免超出边界
      _cx = 0
    } else if (_cx + _width > config.width) {
      _cx = Math.floor(config.width - _width)
    }
    if (_cy < 0) {
      _cy = 0
    } else if (_cy + _height > config.height) {
      _cy = Math.floor(config.height - _height)
    }
    let _selectItem = null
    let _formlist = null
    if (item.subType === 'text') {
      _selectItem = getElement(item.subType, Utils.getuuid(), _cx, _cy, _width, _height)
      _formlist = getTextForm(_selectItem, this.state.fields)
    } else if (item.subType === 'barcode') {
      _selectItem = getElement(item.subType, Utils.getuuid(), _cx, _cy, _width, _height, barurl, config.width)
      _formlist = getBarcodeForm(_selectItem, this.state.fields)
    } else if (item.subType === 'qrcode') {
      _selectItem = getElement(item.subType, Utils.getuuid(), _cx, _cy, _width, _height, qrurl)
      _formlist = getQrcodeForm(_selectItem, this.state.fields)
    } else if (item.subType === 'image') {
      _selectItem = getElement(item.subType, Utils.getuuid(), _cx, _cy, _width, _height, imgurl)
      _formlist = getImageForm(_selectItem, this.state.fields)
    }
    config.elements.push(_selectItem)
    this.setState({
      config: config,
      editItemId: _selectItem.uuid,
      editItemType: _selectItem.type,
      formlist: _formlist
    }, () => {
      this.resetview()
    })
  }
  resetItem = (item) => {
    let _item = JSON.parse(JSON.stringify(item))
    const { config } = this.state
    let _boxwidth = +config.width
    let _boxheight = +config.height
    let _left = +_item.left
    let _top = +_item.top
    let _width = +_item.width
    let _height = +_item.height
    if (_left < 0) {
      _item.left = 0
    }
    if (_top < 0) {
      _item.top = 0
    }
    if (_left + _width > _boxwidth) {
      _item.width = _boxwidth - _left
    }
    if (_top + _height > _boxheight) {
      _item.height = _boxheight - _top
    }
    if (_item.type === 'barcode') {
      if (+_item.barcodeWidth > +_item.width) {
        _item.barcodeWidth = +_item.width
      }
      if (+_item.barcodeHeight > +_item.height) {
        _item.barcodeHeight = +_item.height
      }
    } else if (_item.type === 'qrcode') {
      if (+_item.qrcodeWidth > +_item.width) {
        _item.qrcodeWidth = +_item.width
      }
      if (+_item.qrcodeWidth > +_item.height) {
        _item.qrcodeWidth = +_item.height
      }
    } else if (_item.type === 'image') {
      if (+_item.imgWidth > +_item.width) {
        _item.imgWidth = +_item.width
      }
      if (+_item.imgHeight > +_item.height) {
        _item.imgHeight = +_item.height
      }
    }
    return _item
  }
  handleSubmit = () => {
    const { config } = this.state
    this.FormRef.handleConfirm().then(res => {
      if (res.type === 'Template') {
        res.width = parseInt(res.width)
        res.height = parseInt(res.height)
        if (res.width < 1) {
          res.width = 1
          this.FormRef.resetForm({width: 1})
        } else if (res.height < 1) {
          res.height = 1
          this.FormRef.resetForm({height: 1})
        }
        this.setState({
          config: {...config, ...res}
        }, () => {
          if (res.width !== config.width || res.height !== config.height) {
            this.resetbox()
          }
        })
      } else {
        if (res.type === 'barcode') {
          res.url = barurl
        } else if (res.type === 'qrcode') {
          res.url = qrurl
        } else if (res.type === 'image') {
          res.url = imgurl
        }
        let result = this.resetItem(res)
        if (!is(fromJS(result), fromJS(res))) {
          this.FormRef.resetForm(result)
        }
        config.elements = config.elements.map(item => {
          if (item.uuid === result.uuid) return result
          return item
        })
        this.setState({
          config: config
        }, () => {
          this.resetview()
        })
      }
    })
  }
  deleteItem = () => {
    const _this = this
    const { editItemId, config } = this.state
    confirm({
      title: '确定删除该元素吗?',
      okText: '确定',
      cancelText: '取消',
      onOk() {
        config.elements = config.elements.filter(item => item.uuid !== editItemId)
        _this.setState({
          config: config,
          editItemId: config.uuid,
          editItemType: config.type,
          formlist: getpageform(config)
        }, () => {
          _this.resetview()
        })
      },
      onCancel() {}
    })
  }
  submitConfig = () => {
    const { config } = this.state
    if (config.height / config.width > 10 || config.width / config.height > 10) {
      notification.warning({
        top: 92,
        message: '纸张纵横比不可超过10!',
        duration: 10
      })
      return
    }
    this.setState({
      saveloading: true
    })
    let _config = ''
    try {
      _config = window.btoa(window.encodeURIComponent(JSON.stringify(config)))
    } catch {
      notification.warning({
        top: 92,
        message: '编译错误!',
        duration: 10
      })
      return
    }
    let param = {
      func: 's_PrintTemplateMSub',
      ID: this.state.ID,
      ConfigParam: _config,
      Images: '',
      PrintTempName: config.name,
      Remark: config.remark,
      PrintTempNO: config.PrintTempNO
    }
    new Promise(resolve => {
      printCtrl.sketch(config, null).then(res => {
        Api.fileuploadbase64(res, 'cloud').then(result => { // 图片上传,并获取图片路径
          if (result.status) {
            resolve(Utils.getcloudurl(result.Images))
          } else {
            // notification.warning({
            //   top: 92,
            //   message: result.ErrMesg,
            //   duration: 10
            // })
            // this.setState({
            //   saveloading: false
            // })
            // resolve(false)
            resolve(true)
          }
        })
      })
    }).then(res => {
      if (!res) return
      param.Images = 'http://css.positecgroup.com/Content/Upload/2020-01-08/2020010810525808769824_U000000001.png'
      return Api.getCloudConfig(param)
    }).then(res => {
      if (!res) return
      if (res.status) {
        notification.success({
          top: 92,
          message: '保存成功',
          duration: 2
        })
      } else {
        notification.warning({
          top: 92,
          message: res.ErrMesg,
          duration: 10
        })
      }
      this.setState({
        saveloading: false
      })
    })
  }
@@ -62,10 +710,33 @@
              })}
            </Card>
          </aside>
          <DragElement dropcard={this.dropcard} />
          <aside className="setting">
            <Card title="状态栏">
            </Card>
            {this.state.editItemId ?
              <Card title="状态栏">
                {this.state.formlist ?
                  <MutilForm
                    config={this.state.config}
                    formlist={this.state.formlist}
                    inputSubmit={this.handleSubmit}
                    editItem={{uuid: this.state.editItemId, type: this.state.editItemType}}
                    wrappedComponentRef={(inst) => this.FormRef = inst}
                  /> : null
                }
                <div className="operation">
                  {this.state.editItemType === 'Template' ?
                    <Row gutter={24}>
                      <Button type="primary" onClick={this.submitConfig} loading={this.state.saveloading}>保存</Button>
                    </Row> : null
                  }
                  {this.state.editItemType !== 'Template' ?
                    <Row gutter={24}>
                      <Button type="danger" onClick={this.deleteItem}>删除</Button>
                    </Row> : null
                  }
                </div>
              </Card> : null
            }
          </aside>
        </DndProvider>
      </div>
src/views/printTemplate/index.scss
@@ -1,7 +1,8 @@
.print-template {
  overflow-x: hidden;
  min-height: 100%;
  padding: 48px 250px 0px 240px;
  padding: 75px 250px 30px 240px;
  text-align: center;
  .print-header-container {
    position: fixed;
@@ -23,6 +24,7 @@
    top: 47px;
    left: -1px;
    bottom: 0px;
    text-align: left;
    .ant-card {
      height: 100%;
      .ant-card-head {
@@ -38,11 +40,12 @@
    }
  }
  .setting {
    width: 250px;
    width: 300px;
    position: fixed;
    top: 47px;
    right: -1px;
    bottom: 0px;
    text-align: left;
    .ant-card {
      height: 100%;
      .ant-card-head {
@@ -52,9 +55,38 @@
      .ant-card-head-title {
        padding: 10px 0;
      }
      .ant-card-body {
        padding: 24px 12px;
      .operation {
        text-align: center;
        .ant-btn {
          height: 35px;
          padding: 0px 35px;
        }
      }
      .ant-card-body {
        overflow-y: auto;
        height: calc(100% - 48px);
        padding: 10px 12px 20px;
      }
      .ant-card-body::-webkit-scrollbar {
        width: 7px;
      }
      .ant-card-body::-webkit-scrollbar-thumb {
        border-radius: 5px;
        box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
        background-color: #f90;
        background-image: -webkit-linear-gradient(45deg,hsla(0,0%,100%,.2) 25%,transparent 0,transparent 50%,hsla(0,0%,100%,.2) 0,hsla(0,0%,100%,.2) 75%,transparent 0,transparent);
      }
      .ant-card-body::-webkit-scrollbar-track {
        box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
        border-radius: 3px;
        border: 1px solid rgba(0, 0, 0, 0.07);
        background: rgba(0, 0, 0, 0);
      }
    }
    .ant-form-item {
      margin-bottom: 10px;
    }
  }
}
src/views/printTemplate/mutilform/index.jsx
New file
@@ -0,0 +1,257 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Form, Row, Col, Input, InputNumber, Select } from 'antd'
import { formRule } from '@/utils/option.js'
import FileUpload from '../fileupload'
import './index.scss'
const { TextArea } = Input
class MainSearch extends Component {
  static propTpyes = {
    config: PropTypes.object,     // input回车提交
    inputSubmit: PropTypes.func,  // input回车提交
    editItem: PropTypes.object,   // input回车提交
    formlist: PropTypes.array     // input回车提交
  }
  UNSAFE_componentWillReceiveProps(nextProps) {
    if (!is(fromJS(this.props.editItem), fromJS(nextProps.editItem))) {
      this.setState({}, () => {
        let fieldsvalue = {}
        nextProps.formlist.forEach(item => {
          if (!item.key) return
          fieldsvalue[item.key] = item.initval
        })
        this.props.form.setFieldsValue(fieldsvalue)
      })
    }
  }
  selectChange = (item, value) => {
    if (item.key === 'papertype') {
      let option = item.options.filter(op => op.value === value)[0]
      this.props.form.setFieldsValue({
        width: option.width,
        height: option.height
      })
    }
    this.handleSubmit()
  }
  resetForm = (param) => {
    let _param = JSON.parse(JSON.stringify(param))
    delete _param.type
    delete _param.uuid
    delete _param.url
    this.props.form.setFieldsValue(_param)
  }
  getFields() {
    const { getFieldDecorator } = this.props.form
    const fields = []
    this.props.formlist.forEach((item, index) => {
      if (item.type === 'title') {
        fields.push(
          <Col span={24} key={index}>
            <Form.Item label={item.label} style={{margin: '0px'}}>
              {item.initval}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'text') {
        let _rules = []
        if (item.regular) {
          if (item.regular === 'number') {
            _rules = [{
              pattern: /^[0-9]*$/ig,
              message: formRule.input.numbermsg
            }]
          } else if (item.regular === 'letter') {
            _rules = [{
              pattern: /^[a-zA-Z]*$/ig,
              message: formRule.input.lettermsg
            }]
          } else if (item.regular === 'letter&number') {
            _rules = [{
              pattern: /^[a-zA-Z0-9]*$/ig,
              message: formRule.input.letternummsg
            }]
          }
        }
        fields.push(
          <Col span={24} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.key, {
                initialValue: item.initval || '',
                rules: [
                  {
                    required: !!item.required,
                    message: '请输入' + item.label + '!'
                  },
                  {
                    max: 512,
                    message: formRule.input.formMessage.replace('@max', 512)
                  },
                  ..._rules
                ]
              })(<Input placeholder="" autoComplete="off" onChange={this.handleSubmit} />)}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'number') { // 数字
        let min = item.min || 0
        fields.push(
          <Col span={24} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.key, {
                initialValue: item.initval,
                rules: [
                  {
                    required: true,
                    message: '请输入' + item.label + '!'
                  }
                ]
              })(<InputNumber min={min} precision={item.precision} onChange={(value) => {this.handleSubmit('number', value)}} />)}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'select') { // 下拉搜索
        fields.push(
          <Col span={24} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.key, {
                initialValue: item.initval,
                rules: [
                  {
                    required: !!item.required,
                    message: '请选择' + item.label + '!'
                  }
                ]
              })(
                <Select
                  showSearch
                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
                  getPopupContainer={() => document.getElementById('print-form-box')}
                  onChange={(value) => this.selectChange(item, value)}
                >
                  {item.options.map(option =>
                    <Select.Option id={option.value} title={option.text} key={option.value} value={option.value}>{option.text}</Select.Option>
                  )}
                </Select>
              )}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'fileupload') {
        let filelist = this.props.data ? this.props.data[item.field] : item.initval
        if (filelist && this.state.readin[item.field]) {
          try {
            filelist = filelist.split(',').map((url, index) => {
              return {
                uid: `${index}`,
                name: url.slice(url.lastIndexOf('/') + 1),
                status: 'done',
                url: url,
                origin: true
              }
            })
          } catch {
            filelist = []
          }
        } else {
          filelist = []
        }
        fields.push(
          <Col span={24} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.key, {
                initialValue: filelist,
                rules: [
                  {
                    required: item.required,
                    message: '请选择' + item.label + '!'
                  }
                ]
              })(
                <FileUpload />
              )}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'textarea') {
        fields.push(
          <Col span={24} key={index}>
            <Form.Item label={item.label} >
              {getFieldDecorator(item.key, {
                initialValue: item.initval || '',
                rules: [
                  {
                    required: !!item.required,
                    message: '请输入' + item.label + '!'
                  },
                  {
                    max: 1024,
                    message: formRule.input.formMessage.replace('@max', 1024)
                  }
                ]
              })(<TextArea autosize={{ minRows: 2, maxRows: 6 }} onChange={this.handleSubmit} />)}
            </Form.Item>
          </Col>
        )
      }
    })
    return fields
  }
  handleConfirm = () => {
    // 表单提交时检查输入值是否正确
    return new Promise((resolve, reject) => {
      this.props.form.validateFieldsAndScroll((err, values) => {
        if (!err) {
          values.uuid = this.props.editItem.uuid
          values.type = this.props.editItem.type
          resolve(values)
        }
      })
    })
  }
  handleSubmit = (type, value) => {
    if (type === 'number' && isNaN(parseInt(value))) return
    this.setState({}, () => {
      this.props.inputSubmit()
    })
  }
  render() {
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
        sm: { span: 8 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 16 }
      }
    }
    return (
      <Form {...formItemLayout} className="print-setting-contrl" id="print-form-box">
        <Row gutter={24}>{this.getFields()}</Row>
      </Form>
    )
  }
}
export default Form.create()(MainSearch)
src/views/printTemplate/mutilform/index.scss
New file
@@ -0,0 +1,50 @@
.print-setting-contrl {
  position: relative;
  padding: 0px 0px 20px;
  .ant-form-item {
    display: flex;
  }
  .ant-form-item-control-wrapper {
    flex: 1;
  }
  .ant-form-item-label {
    overflow: hidden;
    display: inline-block;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  // .textarea-row {
  //   .ant-col-sm-3 {
  //     width: 10.5%;
  //   }
  //   .ant-col-sm-21 {
  //     width: 89.5%;
  //   }
  // }
  .ant-input-number {
    width: 100%;
  }
  .ant-form-explain {
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
  }
  p {
    color: #1890ff;
    border-bottom: 1px solid #d9d9d9;
  }
  .ant-input-disabled {
    color: rgba(0, 0, 0, 0.65)!important;
    cursor: default!important;
  }
  .ant-input-number-input {
    color: rgba(0, 0, 0, 0.65)!important;
    cursor: default!important;
  }
  .ant-select-disabled {
    color: rgba(0, 0, 0, 0.65)!important;
    .ant-select-selection--multiple .ant-select-selection__choice {
      color: rgba(0, 0, 0, 0.65)!important;
    }
  }
}
src/views/printTemplate/option.js
New file
@@ -0,0 +1,862 @@
const Fontweight = [
  {
    text: 'normal',
    value: 'normal'
  }, {
    text: 'bold',
    value: 'bold'
  }, {
    text: 'bolder',
    value: 'bolder'
  }, {
    text: 'lighter',
    value: 'lighter'
  }
]
const Color = [
  {
    text: '黑色',
    value: 'black'
  }, {
    text: '红色',
    value: 'red'
  }, {
    text: '灰色',
    value: 'gray'
  }, {
    text: '蓝色',
    value: 'blue'
  }, {
    text: '绿色',
    value: 'green'
  }, {
    text: '白色',
    value: 'white'
  }
]
const Fontfamily = [
  {
    text: '宋体',
    value: 'SimSun'
  }, {
    text: '微软雅黑',
    value: 'Microsoft YaHei'
  }, {
    text: '黑体',
    value: 'SimHei'
  }, {
    text: '微软正黑体',
    value: 'Microsoft JhengHei'
  }, {
    text: '新宋体',
    value: 'NSimSun'
  }, {
    text: '仿宋',
    value: 'FangSong'
  }, {
    text: '楷体',
    value: 'KaiTi'
  }
]
const Rotate = [
  {
    text: '0度',
    value: 0
  }, {
    text: '90度',
    value: 90
  }, {
    text: '180度',
    value: 180
  }, {
    text: '270度',
    value: 270
  }
]
const Align = [
  {
    text: '左对齐',
    value: 'left'
  }, {
    text: '右对齐',
    value: 'right'
  }, {
    text: '居中对齐',
    value: 'center'
  }, {
    text: '两端对齐',
    value: 'justify'
  }
]
const Barcodealign = [
  {
    text: '左对齐',
    value: 'left'
  }, {
    text: '右对齐',
    value: 'right'
  }, {
    text: '居中对齐',
    value: 'center'
  }
]
const VertialAlign = [
  {
    text: '顶部对齐',
    value: 'top'
  }, {
    text: '底部对齐',
    value: 'bottom'
  }, {
    text: '居中对齐',
    value: 'middle'
  }
]
const BarcodeType = [
  {
    text: 'code128',
    value: 'code128'
  }, {
    text: 'EAN13',
    value: 'EAN13'
  }
]
const Boolen = [
  {
    text: '显示',
    value: 'true'
  }, {
    text: '隐藏',
    value: 'false'
  }
]
const QrcodeType = [
  {
    text: 'qrcode',
    value: 'qrcode'
  }
]
// 模板元素
export const printItems = [
  {
    type: 'print',
    label: '文 本',
    subType: 'text',
    icon: 'file-text'
  },
  {
    type: 'print',
    label: '条形码',
    subType: 'barcode',
    icon: 'barcode'
  },
  {
    type: 'print',
    label: '二维码',
    subType: 'qrcode',
    icon: 'qrcode'
  },
  {
    type: 'print',
    label: '图 片',
    subType: 'image',
    icon: 'file-image'
  }
]
// 模板元素
export const originConfig = {
  name: '',
  remark: '',
  papertype: 'resize',
  width: 210,
  height: 297,
  isreadonly: false,
  PrintTempNO: '',
  elements: []
}
export function getpageform (config) {
  return [
    {
      type: 'text',
      key: 'name',
      label: '模板名称',
      initval: config.name,
      required: true
    },
    {
      type: 'textarea',
      key: 'remark',
      label: '描述',
      initval: config.remark,
      required: false
    },
    {
      type: 'select',
      key: 'papertype',
      label: '纸张类型',
      initval: config.papertype,
      required: true,
      options: [{
        text: 'A0',
        value: 'A0',
        width: 841,
        height: 1189
      }, {
        text: 'A1',
        value: 'A1',
        width: 594,
        height: 841
      }, {
        text: 'A2',
        value: 'A2',
        width: 420,
        height: 594
      }, {
        text: 'A3',
        value: 'A3',
        width: 297,
        height: 420
      }, {
        text: 'A4',
        value: 'A4',
        width: 210,
        height: 297
      }, {
        text: '80x50',
        value: '80x50',
        width: 80,
        height: 50
      }, {
        text: '60x40',
        value: '60x40',
        width: 60,
        height: 40
      }, {
        text: '自定义',
        value: 'resize',
        width: 210,
        height: 297
      }]
    },
    {
      type: 'number',
      key: 'width',
      label: '宽度',
      initval: config.width,
      min: 1,
      required: true
    },
    {
      type: 'number',
      key: 'height',
      label: '高度',
      initval: config.height,
      min: 1,
      required: true
    }
  ]
}
export function getElement (type, uuid, cx, cy, width, height, url, boxwidth) {
  let item = {
    uuid: uuid,
    type: type,
    name: '',
    field: '',
    left: cx,
    top: cy,
    width: width,
    height: height,
    rotate: 0,
    borderSize: 1,
    borderColor: 'black',
    align: 'center',
    vertialAlign: 'middle',
    background: 'white'
  }
  if (type === 'text') {
    item.value = ''
    item.fontSize = 12
    item.fontWeight = 'normal'
    item.fontColor = 'black'
    item.fontFamily = 'SimSun'
    item.padding = 1
    item.align = 'left'
    item.vertialAlign = 'top'
  } else if (type === 'barcode') {
    item.url = url
    item.barcodeType = 'code128'
    item.barcodeWidth = Math.floor(width * 0.6)
    item.barcodeHeight = Math.floor(height * 0.4)
    item.barcodeLabel = 'true'
    item.fontSize = Math.floor(12 * (boxwidth / 210))
  } else if (type === 'qrcode') {
    item.url = url
    item.qrcodeType = 'qrcode'
    item.qrcodeWidth = Math.floor(height * 0.6)
  } else if (type === 'image') {
    item.url = url
    item.imgWidth = Math.floor(width * 0.6)
    item.imgHeight = Math.floor(height * 0.5)
  }
  return item
}
export function getTextForm (item, fields) {
  return [
    {
      type: 'title',
      label: '类型',
      initval: '文本',
      required: false
    },
    {
      type: 'text',
      key: 'name',
      label: '名称',
      initval: item.name || '',
      required: false
    },
    {
      type: 'textarea',
      key: 'value',
      label: '内容',
      initval: item.value || '',
      required: false
    },
    {
      type: 'select',
      key: 'field',
      label: '关联字段',
      initval: item.field || '',
      required: false,
      options: fields
    },
    {
      type: 'number',
      key: 'left',
      label: '距左',
      initval: item.left,
      precision: 0,
      required: true
    },
    {
      type: 'number',
      key: 'top',
      label: '距上',
      initval: item.top,
      precision: 0,
      required: true
    },
    {
      type: 'number',
      key: 'width',
      label: '宽度',
      initval: item.width,
      precision: 0,
      required: true
    },
    {
      type: 'number',
      key: 'height',
      label: '高度',
      initval: item.height,
      precision: 0,
      required: true
    },
    {
      type: 'number',
      key: 'fontSize',
      label: '字体大小',
      initval: item.fontSize,
      precision: 0,
      required: true
    },
    {
      type: 'select',
      key: 'fontWeight',
      label: '字体粗细',
      initval: item.fontWeight,
      required: false,
      options: Fontweight
    },
    {
      type: 'select',
      key: 'fontColor',
      label: '字体颜色',
      initval: item.fontColor,
      required: false,
      options: Color
    },
    {
      type: 'select',
      key: 'fontFamily',
      label: '字体名称',
      initval: item.fontFamily,
      required: false,
      options: Fontfamily
    },
    {
      type: 'select',
      key: 'rotate',
      label: '旋转角度',
      initval: item.rotate,
      required: false,
      options: Rotate
    },
    {
      type: 'number',
      key: 'borderSize',
      label: '边框宽度',
      initval: item.borderSize,
      precision: 1,
      required: true
    },
    {
      type: 'select',
      key: 'borderColor',
      label: '边框颜色',
      initval: item.borderColor,
      required: false,
      options: Color
    },
    {
      type: 'number',
      key: 'padding',
      label: '边距',
      initval: item.padding,
      precision: 1,
      required: true
    },
    {
      type: 'select',
      key: 'align',
      label: '水平对齐',
      initval: item.align,
      required: false,
      options: Align
    },
    {
      type: 'select',
      key: 'vertialAlign',
      label: '垂直对齐',
      initval: item.vertialAlign,
      required: false,
      options: VertialAlign
    },
    {
      type: 'select',
      key: 'background',
      label: '背景色',
      initval: item.background,
      required: false,
      options: Color
    }
  ]
}
export function getBarcodeForm (item, fields) {
  return [
    {
      type: 'title',
      label: '类型',
      initval: '条形码',
      required: false
    },
    {
      type: 'text',
      key: 'name',
      label: '名称',
      initval: item.name,
      required: false
    },
    {
      type: 'select',
      key: 'field',
      label: '关联字段',
      initval: item.field,
      required: true,
      options: fields
    },
    {
      type: 'number',
      key: 'left',
      label: '距左',
      initval: item.left,
      precision: 0,
      required: true
    },
    {
      type: 'number',
      key: 'top',
      label: '距上',
      initval: item.top,
      precision: 0,
      required: true
    },
    {
      type: 'number',
      key: 'width',
      label: '宽度',
      initval: item.width,
      precision: 0,
      required: true
    },
    {
      type: 'number',
      key: 'height',
      label: '高度',
      initval: item.height,
      precision: 0,
      required: true
    },
    {
      type: 'select',
      key: 'rotate',
      label: '旋转角度',
      initval: item.rotate,
      required: false,
      options: Rotate
    },
    {
      type: 'number',
      key: 'borderSize',
      label: '边框宽度',
      initval: item.borderSize,
      precision: 1,
      required: true
    },
    {
      type: 'select',
      key: 'borderColor',
      label: '边框颜色',
      initval: item.borderColor,
      required: false,
      options: Color
    },
    {
      type: 'select',
      key: 'align',
      label: '水平对齐',
      initval: item.align,
      required: false,
      options: Barcodealign
    },
    {
      type: 'select',
      key: 'vertialAlign',
      label: '垂直对齐',
      initval: item.vertialAlign,
      required: false,
      options: VertialAlign
    },
    {
      type: 'select',
      key: 'barcodeType',
      label: '编码类型',
      initval: item.barcodeType,
      required: true,
      options: BarcodeType
    },
    {
      type: 'number',
      key: 'barcodeWidth',
      label: '条码宽度',
      initval: item.barcodeWidth,
      precision: 0,
      required: true
    },
    {
      type: 'number',
      key: 'barcodeHeight',
      label: '条码高度',
      initval: item.barcodeHeight,
      precision: 0,
      required: true
    },
    {
      type: 'select',
      key: 'barcodeLabel',
      label: '条码标识',
      initval: item.barcodeLabel,
      required: true,
      options: Boolen
    },
    {
      type: 'number',
      key: 'fontSize',
      label: '字体大小',
      initval: item.fontSize,
      precision: 0,
      required: true
    },
    {
      type: 'select',
      key: 'background',
      label: '背景色',
      initval: item.background,
      required: false,
      options: Color
    }
  ]
}
export function getQrcodeForm (item, fields) {
  return [
    {
      type: 'title',
      label: '类型',
      initval: '二维码',
      required: false
    },
    {
      type: 'text',
      key: 'name',
      label: '名称',
      initval: item.name,
      required: false
    },
    {
      type: 'select',
      key: 'field',
      label: '关联字段',
      initval: item.field,
      required: true,
      options: fields
    },
    {
      type: 'number',
      key: 'left',
      label: '距左',
      initval: item.left,
      precision: 0,
      required: true
    },
    {
      type: 'number',
      key: 'top',
      label: '距上',
      initval: item.top,
      precision: 0,
      required: true
    },
    {
      type: 'number',
      key: 'width',
      label: '宽度',
      initval: item.width,
      precision: 0,
      required: true
    },
    {
      type: 'number',
      key: 'height',
      label: '高度',
      initval: item.height,
      precision: 0,
      required: true
    },
    {
      type: 'select',
      key: 'rotate',
      label: '旋转角度',
      initval: item.rotate,
      required: false,
      options: Rotate
    },
    {
      type: 'number',
      key: 'borderSize',
      label: '边框宽度',
      initval: item.borderSize,
      precision: 1,
      required: true
    },
    {
      type: 'select',
      key: 'borderColor',
      label: '边框颜色',
      initval: item.borderColor,
      required: false,
      options: Color
    },
    {
      type: 'select',
      key: 'align',
      label: '水平对齐',
      initval: item.align,
      required: false,
      options: Barcodealign
    },
    {
      type: 'select',
      key: 'vertialAlign',
      label: '垂直对齐',
      initval: item.vertialAlign,
      required: false,
      options: VertialAlign
    },
    {
      type: 'select',
      key: 'qrcodeType',
      label: '编码类型',
      initval: item.qrcodeType,
      required: true,
      options: QrcodeType
    },
    {
      type: 'number',
      key: 'qrcodeWidth',
      label: '边长',
      initval: item.qrcodeWidth,
      precision: 0,
      required: true
    },
    {
      type: 'select',
      key: 'background',
      label: '背景色',
      initval: item.background,
      required: false,
      options: Color
    }
  ]
}
export function getImageForm (item, fields) {
  return [
    {
      type: 'title',
      label: '类型',
      initval: '图片',
      required: false
    },
    {
      type: 'text',
      key: 'name',
      label: '名称',
      initval: item.name,
      required: false
    },
    // {
    //   type: 'text',
    //   key: 'value',
    //   label: '图片地址',
    //   initval: item.value,
    //   required: false
    // },
    {
      type: 'select',
      key: 'field',
      label: '关联字段',
      initval: item.field,
      required: false,
      options: fields
    },
    {
      type: 'number',
      key: 'left',
      label: '距左',
      initval: item.left,
      precision: 0,
      required: true
    },
    {
      type: 'number',
      key: 'top',
      label: '距上',
      initval: item.top,
      precision: 0,
      required: true
    },
    {
      type: 'number',
      key: 'width',
      label: '宽度',
      initval: item.width,
      precision: 0,
      required: true
    },
    {
      type: 'number',
      key: 'height',
      label: '高度',
      initval: item.height,
      precision: 0,
      required: true
    },
    {
      type: 'select',
      key: 'rotate',
      label: '旋转角度',
      initval: item.rotate,
      required: false,
      options: Rotate
    },
    {
      type: 'number',
      key: 'borderSize',
      label: '边框宽度',
      initval: item.borderSize,
      precision: 1,
      required: true
    },
    {
      type: 'select',
      key: 'borderColor',
      label: '边框颜色',
      initval: item.borderColor,
      required: false,
      options: Color
    },
    {
      type: 'select',
      key: 'align',
      label: '水平对齐',
      initval: item.align,
      required: false,
      options: Barcodealign
    },
    {
      type: 'select',
      key: 'vertialAlign',
      label: '垂直对齐',
      initval: item.vertialAlign,
      required: false,
      options: VertialAlign
    },
    {
      type: 'number',
      key: 'imgWidth',
      label: '图片宽度',
      initval: item.imgWidth,
      precision: 0,
      required: true
    },
    {
      type: 'number',
      key: 'imgHeight',
      label: '图片高度',
      initval: item.imgHeight,
      precision: 0,
      required: true
    },
    {
      type: 'select',
      key: 'background',
      label: '背景色',
      initval: item.background,
      required: false,
      options: Color
    }
  ]
}
export const barurl = require('@/assets/img/barcode.jpg')
export const qrurl = require('@/assets/img/qrcode.png')
export const imgurl = require('@/assets/img/shunfeng.jpg')
src/views/printTemplate/print.js
New file
@@ -0,0 +1,407 @@
export default class Printctrl {
  /**
   * @description 绘制模板至缓存
   * @param  {Object}    configs      配置信息
   * @param  {Boolean}   selectId     编辑元素
   */
  static sketch (configs, selectId) {
    if (!configs.height || !configs.width) return
    if (configs.height / configs.width > 10 || configs.width / configs.height > 10) return
    let ratio = parseInt(document.getElementById('darea').style.width) / configs.width * (window.devicePixelRatio || 1) * 1.5
    let sizeradio = 210 / configs.width * (window.devicePixelRatio || 1) * 1.5
    let canvas = document.createElement('canvas')
    canvas.height = configs.height * ratio
    canvas.width = configs.width * ratio
    let context = canvas.getContext('2d')
    if (configs.elements.length > 0) {
      let elements = JSON.parse(JSON.stringify(configs.elements))
      elements.forEach(element => {
        element.left = element.left * ratio
        element.top = element.top * ratio
        element.width = element.width * ratio
        element.height = element.height * ratio
        if (element.type === 'text') {
          element.padding = element.padding * ratio
          element.fontSize = element.fontSize * sizeradio
        } else if (element.type === 'barcode') {
          element.barcodeWidth = element.barcodeWidth * ratio
          element.barcodeHeight = element.barcodeHeight * ratio
          element.fontSize = element.fontSize * sizeradio
        } else if (element.type === 'qrcode') {
          element.qrcodeWidth = element.qrcodeWidth * ratio
        } else if (element.type === 'image') {
          element.imgWidth = element.imgWidth * ratio
          element.imgHeight = element.imgHeight * ratio
        }
      })
      return new Promise(resolve => {
        this.sketchothers(context, elements, selectId, ratio, resolve)
      })
    } else {
      return new Promise(resolve => {
        this.cachesketch(context, resolve)
      })
    }
  }
  /**
   * @description 绘制图片及文字
   * @param  {Object}    context    画布对象
   * @param  {Object}    elements   图片文字信息
   */
  static sketchothers (context, elements, selectId, ratio, resolve) {
    let element = elements.splice(0, 1)[0] // 逐个绘制图片文字
    let textLineSpace = 5 // 绘制时行间距,防止文字重叠
    context.save()
    if (element.rotate) { // 元素旋转时,设置画布旋转角度
      let _cx = element.left + element.width / 2
      let _cy = element.top + element.height / 2
      context.translate(_cx, _cy) // 移动原点
      context.rotate(element.rotate * Math.PI / 180)
      context.translate(-_cx, -_cy) // 恢复原点
    }
    if (selectId === element.uuid) { // 选中元素,设置外部阴影
      context.shadowBlur = 10
      context.shadowColor = '#757575'
      context.fillStyle = 'white'
      context.fillRect(element.left, element.top, element.width, element.height)
      context.shadowBlur = 0
    }
    // 绘制边框
    // context.rect(element.left + element.borderSize / 2, element.top + element.borderSize / 2, element.width - element.borderSize, element.height - element.borderSize)
    if (element.borderSize >= 1) {
      context.strokeStyle = element.borderColor
      context.lineWidth = element.borderSize
      context.rect(element.left, element.top, element.width, element.height)
      context.stroke()
    }
    // 设置背景色
    if (element.background && element.background !== 'white') {
      context.fillStyle = element.background
      context.fillRect(element.left, element.top, element.width, element.height)
    }
    if (selectId === element.uuid && element.width > 3 * ratio && element.height > 3 * ratio) { // 选中元素,设置外部阴影
      context.strokeStyle = 'black'
      context.beginPath()
      context.moveTo(element.left + element.width - 7, element.top + element.height - 2)
      context.lineTo(element.left + element.width - 2, element.top + element.height - 7)
      context.moveTo(element.left + element.width - 14, element.top + element.height - 2)
      context.lineTo(element.left + element.width - 2, element.top + element.height - 14)
      context.stroke()
    }
    if (!element.width || !element.height) {
      context.restore() // 重置画布
      if (elements.length > 0) {
        this.sketchothers(context, elements, selectId, ratio, resolve)
      } else {
        this.cachesketch(context, resolve)
      }
    } else if (element.type === 'text') {
      // 绘制文字信息
      if (element.fontSize < 12) { // 浏览器最小字体
        textLineSpace += 12 - element.fontSize
      }
      // italic 斜体 small-caps(英文小写字母变成小的大写)
      context.font = 'normal normal ' + element.fontWeight + ' ' + element.fontSize + 'px ' + element.fontFamily
      context.fillStyle = element.fontColor
      let lines = element.value.split('\n')
      let _y = element.top + element.padding + element.fontSize + element.borderSize
      let _left = element.left + element.borderSize + element.padding
      let _right = element.left + element.width - element.padding - element.borderSize
      let _width = _right - _left
      if (element.vertialAlign === 'top') {
        lines.forEach(text => {
          if (!text) {
            _y += element.fontSize + textLineSpace
          }
          let _textArr = []
          let _text = ''
          text.split('').forEach(word => {
            if (context.measureText(_text + word).width <= _width) {
              _text = _text + word
            } else {
              _textArr.push(_text)
              _text = word
            }
          })
          _textArr.forEach(word => {
            let _l = _left
            if (element.align === 'center') {
              _l = _left + (_width - context.measureText(word).width) / 2
            } else if (element.align === 'right') {
              _l = _right - context.measureText(word).width
            } else if (element.align === 'justify') {
              _l = _left + (_width - context.measureText(word).width) / 2
            }
            context.fillText(word, _l, _y)
            _y += element.fontSize + textLineSpace
          })
          if (!_text) {
            return
          }
          if (element.align === 'left') {
            context.fillText(_text, _left, _y)
          } else if (element.align === 'center') {
            context.fillText(_text, _left + (_width - context.measureText(_text).width) / 2, _y)
          } else if (element.align === 'right') {
            context.fillText(_text, _right - context.measureText(_text).width, _y)
          } else if (element.align === 'justify') {
            if (_text.length === 1) {
              context.fillText(_text, _left + (_width - context.measureText(_text).width) / 2, _y)
            } else {
              let _dleft = _left
              _text.split('').forEach(_word => {
                context.fillText(_word, _dleft, _y)
                _dleft += (_width - context.measureText(_text).width) / (_text.length - 1) + context.measureText(_word).width
              })
            }
          }
          _y += element.fontSize + textLineSpace
        })
      } else if (element.vertialAlign === 'middle' || element.vertialAlign === 'bottom') {
        let lineheight = 0
        lines.forEach(text => {
          if (!text) {
            lineheight += element.fontSize + textLineSpace
            return
          }
          lineheight += Math.ceil(context.measureText(text).width / _width) * (element.fontSize + textLineSpace)
        })
        if (element.vertialAlign === 'middle') {
          _y += (element.height - element.padding * 2 - element.borderSize * 2 - lineheight) / 2
        } else {
          _y += element.height - element.padding * 2 - element.borderSize * 2 - lineheight
        }
        lines.forEach(text => {
          if (!text) {
            _y += element.fontSize + textLineSpace
          }
          let _textArr = []
          let _text = ''
          text.split('').forEach(word => {
            if (context.measureText(_text + word).width <= _width) {
              _text = _text + word
            } else {
              _textArr.push(_text)
              _text = word
            }
          })
          _textArr.forEach(word => {
            let _l = _left
            if (element.align === 'center') {
              _l = _left + (_width - context.measureText(word).width) / 2
            } else if (element.align === 'right') {
              _l = _right - context.measureText(word).width
            } else if (element.align === 'justify') {
              _l = _left + (_width - context.measureText(word).width) / 2
            }
            context.fillText(word, _l, _y)
            _y += element.fontSize + textLineSpace
          })
          if (!_text) {
            return
          }
          if (element.align === 'left') {
            context.fillText(_text, _left, _y)
          } else if (element.align === 'center') {
            context.fillText(_text, _left + (_width - context.measureText(_text).width) / 2, _y)
          } else if (element.align === 'right') {
            context.fillText(_text, _right - context.measureText(_text).width, _y)
          } else if (element.align === 'justify') {
            if (_text.length === 1) {
              context.fillText(_text, _left + (_width - context.measureText(_text).width) / 2, _y)
            } else {
              let _dleft = _left
              _text.split('').forEach(_word => {
                context.fillText(_word, _dleft, _y)
                _dleft += (_width - context.measureText(_text).width) / (_text.length - 1) + context.measureText(_word).width
              })
            }
          }
          _y += element.fontSize + textLineSpace
        })
      }
      context.restore() // 重置画布
      if (elements.length > 0) {
        this.sketchothers(context, elements, selectId, ratio, resolve)
      } else {
        this.cachesketch(context, resolve)
      }
    } else if (element.type === 'barcode') {
      let _space = 5
      let _left = element.left
      let _top = element.top
      if (element.vertialAlign === 'middle') {
        if (element.barcodeLabel === 'true') {
          _top = element.top + (element.height - element.barcodeHeight - element.fontSize - _space) / 2
        } else {
          _top = element.top + (element.height - element.barcodeHeight) / 2
        }
      } else if (element.vertialAlign === 'bottom') {
        if (element.barcodeLabel === 'true') {
          _top = element.top + (element.height - element.barcodeHeight - element.fontSize - _space)
        } else {
          _top = element.top + element.height - element.barcodeHeight
        }
      }
      if (element.align === 'center') {
        _left = element.left + (element.width - element.barcodeWidth) / 2
      } else if (element.align === 'right') {
        _left = element.left + element.width - element.barcodeWidth
      }
      context.font = 'normal normal normal ' + element.fontSize + 'px Microsoft YaHei'
      context.fillStyle = 'black'
      let text = '1234567890123'
      let _tleft = _left + (element.barcodeWidth - context.measureText(text).width) / 2
      let _ttop = _top + element.barcodeHeight + _space + element.fontSize
      let image = new Image()
      image.src = element.url
      if (image.complete) {
        context.drawImage(image, _left, _top, element.barcodeWidth, element.barcodeHeight)
        if (element.barcodeLabel === 'true') {
          context.fillText(text, _tleft, _ttop)
        }
        context.restore() // 重置画布
        if (elements.length > 0) {
          this.sketchothers(context, elements, selectId, ratio, resolve)
        } else {
          this.cachesketch(context, resolve)
        }
      } else {
        image.onload = () => {
          context.drawImage(image, _left, _top, element.barcodeWidth, element.barcodeHeight)
          if (element.barcodeLabel === 'true') {
            context.fillText(text, _tleft, _ttop)
          }
          context.restore() // 重置画布
          if (elements.length > 0) {
            this.sketchothers(context, elements, selectId, ratio, resolve)
          } else {
            this.cachesketch(context, resolve)
          }
        }
      }
    } else if (element.type === 'qrcode') {
      let _left = element.left
      let _top = element.top
      if (element.vertialAlign === 'middle') {
        _top = element.top + (element.height - element.qrcodeWidth) / 2
      } else if (element.vertialAlign === 'bottom') {
        _top = element.top + element.height - element.qrcodeWidth
      }
      if (element.align === 'center') {
        _left = element.left + (element.width - element.qrcodeWidth) / 2
      } else if (element.align === 'right') {
        _left = element.left + element.width - element.qrcodeWidth
      }
      let image = new Image()
      image.src = element.url
      if (image.complete) {
        context.drawImage(image, _left, _top, element.qrcodeWidth, element.qrcodeWidth)
        context.restore() // 重置画布
        if (elements.length > 0) {
          this.sketchothers(context, elements, selectId, ratio, resolve)
        } else {
          this.cachesketch(context, resolve)
        }
      } else {
        image.onload = () => {
          context.drawImage(image, _left, _top, element.qrcodeWidth, element.qrcodeWidth)
          context.restore() // 重置画布
          if (elements.length > 0) {
            this.sketchothers(context, elements, selectId, ratio, resolve)
          } else {
            this.cachesketch(context, resolve)
          }
        }
      }
    } else if (element.type === 'image') {
      let _left = element.left
      let _top = element.top
      if (element.vertialAlign === 'middle') {
        _top = element.top + (element.height - element.imgHeight) / 2
      } else if (element.vertialAlign === 'bottom') {
        _top = element.top + element.height - element.imgHeight
      }
      if (element.align === 'center') {
        _left = element.left + (element.width - element.imgWidth) / 2
      } else if (element.align === 'right') {
        _left = element.left + element.width - element.imgWidth
      }
      let image = new Image()
      image.src = element.value || element.url
      if (image.complete) {
        context.drawImage(image, _left, _top, element.imgWidth, element.imgHeight)
        context.restore() // 重置画布
        if (elements.length > 0) {
          this.sketchothers(context, elements, selectId, ratio, resolve)
        } else {
          this.cachesketch(context, resolve)
        }
      } else {
        image.onload = () => {
          context.drawImage(image, _left, _top, element.imgWidth, element.imgHeight)
          context.restore() // 重置画布
          if (elements.length > 0) {
            this.sketchothers(context, elements, selectId, ratio, resolve)
          } else {
            this.cachesketch(context, resolve)
          }
        }
      }
    }
  }
  /**
   * @description 绘制模板值页面
   * @param  {Object}    configs      配置信息
   */
  static cachesketch (context, resolve) {
    let cacheCanvas = context.canvas
    let canvas = document.getElementById('darea')
    canvas.width = cacheCanvas.width
    canvas.height = cacheCanvas.height
    let ctx = canvas.getContext('2d')
    ctx.clearRect(0, 0, canvas.width + 1, canvas.height + 1)
    ctx.beginPath()
    ctx.fillStyle = 'white'
    ctx.fillRect(0, 0, canvas.width + 1, canvas.height + 1)
    ctx.drawImage(cacheCanvas, 0, 0, canvas.width, canvas.height)
    resolve(canvas.toDataURL('image/png'))
  }
}