From e2ac71fbc53b7119ae87c5a3b08cdcf830b497e2 Mon Sep 17 00:00:00 2001
From: king <18310653075@163.com>
Date: 星期五, 06 三月 2020 18:52:03 +0800
Subject: [PATCH] 2020-03-06

---
 src/assets/img/qrcode.png                      |    0 
 src/assets/img/barcode.jpg                     |    0 
 src/views/printTemplate/option.js              |  862 ++++++++++++++++++
 src/views/printTemplate/index.jsx              |  735 +++++++++++++++
 src/assets/img/shunfeng.jpg                    |    0 
 src/views/printTemplate/index.scss             |   40 
 src/views/printTemplate/mutilform/index.jsx    |  257 +++++
 src/templates/formtabconfig/index.jsx          |   18 
 src/views/printTemplate/fileupload/index.jsx   |  140 +++
 src/templates/comtableconfig/index.jsx         |   19 
 src/views/printTemplate/dragelement/index.jsx  |   37 
 src/views/printTemplate/mutilform/index.scss   |   50 +
 /dev/null                                      |    8 
 src/templates/modalconfig/index.jsx            |   27 
 src/views/printTemplate/print.js               |  407 ++++++++
 src/api/index.js                               |   88 +
 src/views/printTemplate/dragelement/index.scss |   10 
 src/tabviews/commontable/index.jsx             |   10 
 src/views/printTemplate/fileupload/index.scss  |    5 
 src/utils/utils.js                             |   20 
 20 files changed, 2,653 insertions(+), 80 deletions(-)

diff --git a/src/api/index.js b/src/api/index.js
index 5a879a0..19c2481 100644
--- a/src/api/index.js
+++ b/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) {
diff --git a/src/assets/img/barcode.jpg b/src/assets/img/barcode.jpg
new file mode 100644
index 0000000..252e89c
--- /dev/null
+++ b/src/assets/img/barcode.jpg
Binary files differ
diff --git a/src/assets/img/qrcode.png b/src/assets/img/qrcode.png
new file mode 100644
index 0000000..895b409
--- /dev/null
+++ b/src/assets/img/qrcode.png
Binary files differ
diff --git a/src/assets/img/shunfeng.jpg b/src/assets/img/shunfeng.jpg
new file mode 100644
index 0000000..ed6f520
--- /dev/null
+++ b/src/assets/img/shunfeng.jpg
Binary files differ
diff --git a/src/tabviews/commontable/index.jsx b/src/tabviews/commontable/index.jsx
index 526ae53..fa3a891 100644
--- a/src/tabviews/commontable/index.jsx
+++ b/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') {
diff --git a/src/templates/comtableconfig/index.jsx b/src/templates/comtableconfig/index.jsx
index 7fb6751..bd48173 100644
--- a/src/templates/comtableconfig/index.jsx
+++ b/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`)
         }
 
diff --git a/src/templates/formtabconfig/index.jsx b/src/templates/formtabconfig/index.jsx
index 0005835..ee46115 100644
--- a/src/templates/formtabconfig/index.jsx
+++ b/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,
diff --git a/src/templates/modalconfig/index.jsx b/src/templates/modalconfig/index.jsx
index b655b80..4f50489 100644
--- a/src/templates/modalconfig/index.jsx
+++ b/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)
 
diff --git a/src/utils/utils.js b/src/utils/utils.js
index b5c9245..9edfb85 100644
--- a/src/utils/utils.js
+++ b/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   鎼滅储鏉′欢淇℃伅
    */
diff --git a/src/views/printTemplate/dragelement/card.jsx b/src/views/printTemplate/dragelement/card.jsx
deleted file mode 100644
index 5419ea0..0000000
--- a/src/views/printTemplate/dragelement/card.jsx
+++ /dev/null
@@ -1,158 +0,0 @@
-import React from 'react'
-import { useDrag, useDrop } from 'react-dnd'
-import { Icon, Button, Select, DatePicker, Input } from 'antd'
-import moment from 'moment'
-import ItemTypes from './itemtypes'
-import './index.scss'
-
-const { MonthPicker, WeekPicker, RangePicker } = DatePicker
-// const { Paragraph } = Typography
-
-const Card = ({ id, type, card, moveCard, findCard, editCard, delCard, copyCard, profileCard, hasDrop, showfield }) => {
-  const originalIndex = findCard(id).index
-  const [{ isDragging }, drag] = useDrag({
-    item: { type: ItemTypes[type], id, originalIndex },
-    collect: monitor => ({
-      isDragging: monitor.isDragging(),
-    }),
-  })
-  const [, drop] = useDrop({
-    accept: ItemTypes[type],
-    canDrop: () => true,
-    drop: (item) => {
-      if (!item.hasOwnProperty('originalIndex')) {
-        hasDrop(card)
-      }
-    },
-    hover({ id: draggedId }) {
-      if (!draggedId) return
-      if (draggedId !== id) {
-        const { index: overIndex } = findCard(id)
-        moveCard(draggedId, overIndex)
-      }
-    },
-  })
-  const opacity = isDragging ? 0 : 1
-
-  const edit = () => {
-    editCard(id)
-  }
-  
-  const del = () => {
-    delCard(id)
-  }
-
-  const copy = () => {
-    copyCard(id)
-  }
-  
-  const profile = () => {
-    profileCard(id)
-  }
-
-  let _defaultValue = '' // 涓嬫媺鎼滅储銆佹椂闂磋寖鍥寸被鍨嬶紝鍒濆鍊奸渶瑕侀澶勭悊
-
-  if (type === 'search' && (card.type === 'multiselect' || card.type === 'select' || card.type === 'link')) {
-    if (card.initval) {
-      let _option = card.options.filter(option => option.Value === card.initval)[0]
-      if (_option) {
-        _defaultValue = _option.Text || ''
-      } else {
-        _defaultValue = ''
-      }
-    } else if (card.setAll === 'true') {
-      _defaultValue = '鍏ㄩ儴'
-    }
-  } else if (type === 'search' && card.type === 'daterange') {
-    _defaultValue = [null, null]
-    if (card.initval) {
-      try {
-        let _initval = JSON.parse(card.initval)
-        _defaultValue = [moment().subtract(_initval[0], 'days'), moment().subtract(_initval[1], 'days')]
-      } catch {
-        _defaultValue = [null, null]
-      }
-    }
-  }
-
-  let hasProfile = false
-  if (type === 'action') {
-    if (['pop', 'prompt', 'exec'].includes(card.OpenType) && card.intertype === 'inner' && !card.innerFunc) {
-      hasProfile = true
-    } else if (card.OpenType === 'excelIn' || card.OpenType === 'excelOut') {
-      hasProfile = true
-    }
-  }
-
-  return (
-    <div className="page-card" style={type === 'columns' ? { flex: card.Width, opacity: opacity} : { opacity: opacity}}>
-      <div ref={node => drag(drop(node))}>
-        {type === 'search' ?
-          <div className="ant-row ant-form-item">
-            <div className="ant-col ant-form-item-label">
-              <label title={card.label}>{card.label}</label>
-            </div>
-            <div className="ant-col ant-form-item-control-wrapper">
-              {card.type === 'text' ?
-                <Input style={{marginTop: '4px'}} defaultValue={card.initval} /> : null
-              }
-              {(card.type === 'multiselect' || card.type === 'select' || card.type === 'link') ?
-                <Select defaultValue={_defaultValue}></Select> : null
-              }
-              {card.type === 'date' ?
-                <DatePicker defaultValue={card.initval ? moment().subtract(card.initval, 'days') : null} /> : null
-              }
-              {card.type === 'dateweek' ?
-                <WeekPicker defaultValue={card.initval ? moment().subtract(card.initval * 7, 'days') : null} /> : null
-              }
-              {card.type === 'datemonth' ?
-                <MonthPicker defaultValue={card.initval ? moment().subtract(card.initval, 'month') : null} /> : null
-              }
-              {card.type === 'daterange' ?
-                <RangePicker
-                  className="data-range"
-                  placeholder={['寮�濮嬫棩鏈�', '缁撴潫鏃ユ湡']}
-                  renderExtraFooter={() => 'extra footer'}
-                  defaultValue={_defaultValue}
-                /> : null
-              }
-              <div className="input-mask"></div>
-            </div>
-          </div> : null
-        }
-        {type === 'action' ?
-          <Button
-            className={'mk-btn mk-' + card.class}
-            icon={card.icon}
-            key={card.uuid}
-          >
-            {card.label}{card.position === 'grid' && <Icon type="table" />}
-          </Button> : null
-        }
-        {type === 'columns' ?
-          <span className="ant-table-header-column">
-            <div className="ant-table-column-sorters" title={card.label} style={{textAlign: card.Align}}>
-              <span className="ant-table-column-title">{card.label}</span>
-              {card.IsSort === 'true' ?
-                <span className="ant-table-column-sorter">
-                  <Icon type="caret-up" />
-                  <Icon type="caret-down" />
-                </span> : null
-              }
-            </div>
-            {showfield ?
-              <div className="ant-table-column-fields">
-                <span className="ant-table-column-title">{card.type === 'colspan' ? card.subfield : card.field}</span>
-              </div> : null
-            }
-          </span> : null
-        }
-      </div>
-      <Icon className="edit" title="缂栬緫" type="edit" onClick={edit} />
-      <Icon className="edit close" title="鍒犻櫎" type="close" onClick={del} />
-      {type === 'action' ? <Icon className="edit copy" title="澶嶅埗" type="copy" onClick={copy} /> : null}
-      {hasProfile ? <Icon className="edit profile" title="鏍¢獙瑙勫垯" type="profile" onClick={profile} /> : null}
-    </div>
-  )
-}
-export default Card
diff --git a/src/views/printTemplate/dragelement/index.jsx b/src/views/printTemplate/dragelement/index.jsx
index 291bb24..242eb21 100644
--- a/src/views/printTemplate/dragelement/index.jsx
+++ b/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>
   )
 }
diff --git a/src/views/printTemplate/dragelement/index.scss b/src/views/printTemplate/dragelement/index.scss
index 90174bc..bf335cf 100644
--- a/src/views/printTemplate/dragelement/index.scss
+++ b/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);
+  }
+}
+
diff --git a/src/views/printTemplate/dragelement/itemtypes.js b/src/views/printTemplate/dragelement/itemtypes.js
deleted file mode 100644
index 9ea1f2c..0000000
--- a/src/views/printTemplate/dragelement/itemtypes.js
+++ /dev/null
@@ -1,8 +0,0 @@
-export default {
-  CARD: 'card',
-  form: 'form',
-  search: 'search',
-  action: 'action',
-  columns: 'columns',
-  tab: 'tab'
-}
diff --git a/src/views/printTemplate/fileupload/index.jsx b/src/views/printTemplate/fileupload/index.jsx
new file mode 100644
index 0000000..682498f
--- /dev/null
+++ b/src/views/printTemplate/fileupload/index.jsx
@@ -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
\ No newline at end of file
diff --git a/src/views/printTemplate/fileupload/index.scss b/src/views/printTemplate/fileupload/index.scss
new file mode 100644
index 0000000..1bee6cc
--- /dev/null
+++ b/src/views/printTemplate/fileupload/index.scss
@@ -0,0 +1,5 @@
+.main-form-field .ant-progress-small.ant-progress-line {
+  position: absolute;
+  bottom: -20px;
+  left: 0px;
+}
\ No newline at end of file
diff --git a/src/views/printTemplate/index.jsx b/src/views/printTemplate/index.jsx
index 69f6f17..fc31b6a 100644
--- a/src/views/printTemplate/index.jsx
+++ b/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: '閰嶇疆淇℃伅瑙f瀽閿欒锛�',
+            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>
diff --git a/src/views/printTemplate/index.scss b/src/views/printTemplate/index.scss
index a742905..3eb4643 100644
--- a/src/views/printTemplate/index.scss
+++ b/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;
     }
   }
+  
 }
\ No newline at end of file
diff --git a/src/views/printTemplate/mutilform/index.jsx b/src/views/printTemplate/mutilform/index.jsx
new file mode 100644
index 0000000..2d3dbf0
--- /dev/null
+++ b/src/views/printTemplate/mutilform/index.jsx
@@ -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)
\ No newline at end of file
diff --git a/src/views/printTemplate/mutilform/index.scss b/src/views/printTemplate/mutilform/index.scss
new file mode 100644
index 0000000..2b92a82
--- /dev/null
+++ b/src/views/printTemplate/mutilform/index.scss
@@ -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;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/views/printTemplate/option.js b/src/views/printTemplate/option.js
new file mode 100644
index 0000000..ca9317b
--- /dev/null
+++ b/src/views/printTemplate/option.js
@@ -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: '寰蒋姝i粦浣�',
+    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')
\ No newline at end of file
diff --git a/src/views/printTemplate/print.js b/src/views/printTemplate/print.js
new file mode 100644
index 0000000..f6b5be1
--- /dev/null
+++ b/src/views/printTemplate/print.js
@@ -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'))
+  }
+}

--
Gitblit v1.8.0