From 9b6ce1a5778c6e1a813237e87588c0052aae1bbb Mon Sep 17 00:00:00 2001
From: king <18310653075@163.com>
Date: 星期三, 29 四月 2020 17:26:15 +0800
Subject: [PATCH] 2020-04-29

---
 src/templates/sharecomponent/columncomponent/columnform/index.scss                 |   19 
 src/templates/sharecomponent/chartgroupcomponent/searchform/index.scss             |   24 
 src/templates/sharecomponent/actioncomponent/verifyexcelout/columnform/index.scss  |    0 
 src/templates/zshare/viewdragelement/index.scss                                    |   41 
 src/assets/img/微信图片_20200426165043.png                                             |    0 
 src/templates/sharecomponent/actioncomponent/verifyprint/editable/index.jsx        |  241 
 src/templates/zshare/verifycard/customscript/index.jsx                             |   45 
 src/assets/img/bar3.png                                                            |    0 
 src/locales/zh-CN/model.js                                                         |   24 
 src/templates/zshare/chartcomponent/index.jsx                                      |  437 +
 src/templates/modalconfig/index.jsx                                                |   18 
 src/templates/sharecomponent/searchcomponent/searchform/index.scss                 |   24 
 src/templates/sharecomponent/actioncomponent/verifyexcelin/customscript/index.jsx  |  296 +
 src/templates/sharecomponent/tablecomponent/index.jsx                              |  455 +
 src/tabviews/commontable/index.jsx                                                 |    2 
 src/templates/sharecomponent/actioncomponent/verifyexcelin/index.jsx               |  825 +++
 src/templates/sharecomponent/actioncomponent/dragaction/card.jsx                   |   60 
 src/assets/css/main.scss                                                           |   25 
 src/assets/img/A_qpizTrPVB-IAAAAAAAAAAABkARQnAQ.png                                |    0 
 src/assets/img/pie1.png                                                            |    0 
 src/templates/sharecomponent/actioncomponent/verifyexcelout/columnform/index.jsx   |  127 
 src/assets/img/A_aFXQS7yyDyUAAAAAAAAAAABkARQnAQ.png                                |    0 
 src/templates/subtableconfig/index.jsx                                             | 1697 -----
 src/templates/zshare/exceleditable/index.jsx                                       |    2 
 src/assets/img/bar1.png                                                            |    0 
 src/templates/sharecomponent/columncomponent/dragcolumn/index.scss                 |    6 
 src/templates/sharecomponent/searchcomponent/searcheditable/index.jsx              |  265 
 src/templates/sharecomponent/columncomponent/colspanform/index.scss                |    8 
 src/templates/zshare/viewdragelement/card.jsx                                      |   48 
 package-lock.json                                                                  |  194 
 src/templates/sharecomponent/actioncomponent/verifyexcelin/columnform/index.jsx    |  202 
 src/assets/img/line3.png                                                           |    0 
 src/templates/sharecomponent/actioncomponent/verifyexcelin/uniqueform/index.jsx    |  149 
 src/templates/zshare/viewdragelement/index.jsx                                     |   85 
 src/templates/comtableconfig/index.jsx                                             |   66 
 src/templates/sharecomponent/searchcomponent/dragsearch/card.jsx                   |  101 
 src/templates/zshare/verifycardexcelin/index.jsx                                   |   14 
 src/components/dragelement/index.jsx                                               |    2 
 src/templates/sharecomponent/chartgroupcomponent/dragchartview/index.scss          |   41 
 src/templates/zshare/chartcomponent/index.scss                                     |    7 
 src/templates/sharecomponent/chartgroupcomponent/searcheditable/index.scss         |   36 
 src/templates/sharecomponent/columncomponent/dragcolumn/index.jsx                  |  165 
 src/tabviews/subtable/index.jsx                                                    |    2 
 src/templates/sharecomponent/actioncomponent/index.scss                            |   84 
 src/templates/zshare/modaleditable/index.jsx                                       |    4 
 src/assets/img/line1.png                                                           |    0 
 src/templates/sharecomponent/actioncomponent/verifyprint/index.jsx                 |  461 +
 src/templates/sharecomponent/searchcomponent/searcheditable/index.scss             |   36 
 src/templates/comtableconfig/source.jsx                                            |    4 
 src/templates/sharecomponent/columncomponent/dragcolumn/card.jsx                   |   58 
 src/templates/sharecomponent/searchcomponent/dragsearch/index.jsx                  |  155 
 src/assets/img/bar4.png                                                            |    0 
 src/templates/subtableconfig/index.scss                                            |  262 
 src/templates/sharecomponent/fieldscomponent/index.scss                            |   27 
 src/templates/sharecomponent/searchcomponent/dragsearch/index.scss                 |    6 
 src/templates/modalconfig/source.jsx                                               |    4 
 src/templates/zshare/verifycardprint/editable/index.jsx                            |    2 
 src/templates/sharecomponent/actioncomponent/dragaction/index.jsx                  |  179 
 src/components/sidemenu/index.jsx                                                  |    2 
 src/templates/sharecomponent/actioncomponent/dragaction/index.scss                 |    6 
 src/templates/zshare/transferform/index.scss                                       |    4 
 src/templates/zshare/chartform/index.scss                                          |   25 
 src/templates/sharecomponent/chartgroupcomponent/dragchartview/card.jsx            |   48 
 src/templates/zshare/chartform/index.jsx                                           |  379 +
 src/templates/sharecomponent/actioncomponent/actionform/index.scss                 |   33 
 src/templates/sharecomponent/actioncomponent/verifyexcelin/customscript/index.scss |    0 
 src/assets/img/bar2.png                                                            |    0 
 src/templates/sharecomponent/chartgroupcomponent/searcheditable/index.jsx          |  265 
 src/templates/sharecomponent/fieldscomponent/editcard/index.jsx                    |  157 
 src/templates/sharecomponent/columncomponent/gridbtnform/index.scss                |    8 
 src/templates/formtabconfig/source.jsx                                             |    4 
 src/components/sidemenu/config.jsx                                                 |    0 
 src/templates/sharecomponent/chartgroupcomponent/chartform/index.scss              |   25 
 src/templates/sharecomponent/actioncomponent/verifyexcelin/index.scss              |   70 
 src/templates/sharecomponent/actioncomponent/actionform/index.jsx                  |  657 ++
 src/templates/sharecomponent/columncomponent/index.scss                            |   85 
 src/templates/sharecomponent/actioncomponent/verifyexcelin/columnform/index.scss   |    0 
 src/templates/zshare/pasteform/index.jsx                                           |    5 
 src/templates/zshare/chartcompile/index.jsx                                        |  213 
 src/templates/sharecomponent/tablecomponent/index.scss                             |    7 
 src/assets/img/pie2.png                                                            |    0 
 src/templates/sharecomponent/columncomponent/gridbtnform/index.jsx                 |  218 
 src/templates/zshare/createinterface/index.jsx                                     |   33 
 src/templates/sharecomponent/actioncomponent/verifyexcelout/index.scss             |   62 
 src/templates/sharecomponent/searchcomponent/index.scss                            |   84 
 src/templates/sharecomponent/searchcomponent/searchform/index.jsx                  |  475 +
 src/templates/subtableconfig/source.jsx                                            |   16 
 src/templates/zshare/verifycardexcelout/index.jsx                                  |    4 
 src/templates/formtabconfig/index.jsx                                              |   28 
 src/templates/sharecomponent/chartgroupcomponent/index.scss                        |   24 
 src/templates/sharecomponent/searchcomponent/index.jsx                             |  280 +
 src/templates/zshare/editcomponent/index.jsx                                       |   17 
 src/templates/sharecomponent/fieldscomponent/index.jsx                             |  252 
 src/templates/sharecomponent/actioncomponent/verifyprint/editable/index.scss       |   48 
 src/templates/sharecomponent/columncomponent/index.jsx                             |  437 +
 src/templates/zshare/verifycard/customform/index.jsx                               |    6 
 src/templates/sharecomponent/columncomponent/colspanform/index.jsx                 |  193 
 src/locales/en-US/model.js                                                         |   24 
 src/assets/img/line4.png                                                           |    0 
 src/templates/sharecomponent/chartgroupcomponent/chartform/index.jsx               |  379 +
 src/templates/zshare/chartcompile/index.scss                                       |   31 
 src/utils/utils.js                                                                 |    2 
 src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx              |  339 +
 src/templates/sharecomponent/fieldscomponent/editcard/index.scss                   |   49 
 src/templates/zshare/formconfig.jsx                                                |  377 +
 src/templates/zshare/verifycard/index.jsx                                          |  287 
 src/templates/zshare/tabdragelement/card.jsx                                       |    2 
 src/templates/sharecomponent/actioncomponent/verifyprint/index.scss                |   60 
 src/tabviews/zshare/verifycard/index.jsx                                           |    2 
 src/templates/sharecomponent/actioncomponent/index.jsx                             |  921 +++
 src/assets/img/line2.png                                                           |    0 
 src/templates/sharecomponent/chartgroupcomponent/searchform/index.jsx              |  475 +
 package.json                                                                       |    1 
 src/templates/sharecomponent/chartgroupcomponent/dragchartview/index.jsx           |   74 
 src/utils/modelutils.js                                                            | 1620 +++++
 src/templates/sharecomponent/actioncomponent/verifyexcelin/uniqueform/index.scss   |    0 
 src/templates/sharecomponent/chartgroupcomponent/index.jsx                         |  234 
 src/templates/sharecomponent/columncomponent/columnform/index.jsx                  |  376 +
 118 files changed, 14,560 insertions(+), 1,898 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index de3c4c6..005b31c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -87,6 +87,29 @@
         "tslib": "1.10.0"
       }
     },
+    "@antv/data-set": {
+      "version": "0.11.4",
+      "resolved": "https://registry.npmjs.org/@antv/data-set/-/data-set-0.11.4.tgz",
+      "integrity": "sha512-rS0xMvclsv59wh2yDmCshC55/HvXBbwpEmoTr+ErSY4SKGKSTOwXjZ90W/fJMSfacMPOGDbG7R77kCP8cSTu5w==",
+      "requires": {
+        "@antv/hierarchy": "0.6.3",
+        "@antv/util": "2.0.8",
+        "d3-composite-projections": "1.3.2",
+        "d3-dsv": "1.2.0",
+        "d3-geo": "1.6.4",
+        "d3-geo-projection": "2.1.2",
+        "d3-hexjson": "1.1.0",
+        "d3-hierarchy": "1.1.9",
+        "d3-sankey": "0.9.1",
+        "d3-voronoi": "1.1.4",
+        "dagre": "0.8.5",
+        "point-at-length": "1.1.0",
+        "regression": "2.0.1",
+        "simple-statistics": "6.1.1",
+        "topojson-client": "3.1.0",
+        "wolfy87-eventemitter": "5.2.9"
+      }
+    },
     "@antv/dom-util": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/@antv/dom-util/-/dom-util-2.0.2.tgz",
@@ -194,6 +217,14 @@
       "version": "2.7.1",
       "resolved": "https://registry.npmjs.org/@antv/gl-matrix/-/gl-matrix-2.7.1.tgz",
       "integrity": "sha512-oOWcVNlpELIKi9x+Mm1Vwbz8pXfkbJKykoCIOJ/dNK79hSIANbpXJ5d3Rra9/wZqK6MC961B7sybFhPlLraT3Q=="
+    },
+    "@antv/hierarchy": {
+      "version": "0.6.3",
+      "resolved": "https://registry.npmjs.org/@antv/hierarchy/-/hierarchy-0.6.3.tgz",
+      "integrity": "sha512-91YZUiZFXK8zp2nC2C+4FEc1LDIPZ5Q4YQbzMnKhH+7nei4QCfIdXPrPh0EKRws78CVt2hxR5gHD7zq6UlokAQ==",
+      "requires": {
+        "@antv/util": "2.0.8"
+      }
     },
     "@antv/matrix-util": {
       "version": "2.0.7",
@@ -2065,6 +2096,11 @@
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
       "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
+    },
+    "abs-svg-path": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/abs-svg-path/-/abs-svg-path-0.1.1.tgz",
+      "integrity": "sha1-32Acjo0roQ1KdtYl4japo5wnI78="
     },
     "accepts": {
       "version": "1.3.7",
@@ -4413,15 +4449,85 @@
         "type": "1.0.3"
       }
     },
+    "d3-array": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz",
+      "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw=="
+    },
+    "d3-collection": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.7.tgz",
+      "integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A=="
+    },
     "d3-color": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.0.tgz",
       "integrity": "sha512-TzNPeJy2+iEepfiL92LAAB7fvnp/dV2YwANPVHdDWmYMm23qIJBYww3qT8I8C1wXrmrg4UWs7BKc2tKIgyjzHg=="
     },
+    "d3-composite-projections": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/d3-composite-projections/-/d3-composite-projections-1.3.2.tgz",
+      "integrity": "sha512-dao+Dd/EEYBX+FqNYwe/4putAsMXWewSgDj5sETRFsj1z4X/CVI6ctmZhqvpa/MVYCFHoWV9Issu+20OU5VmbA==",
+      "requires": {
+        "d3-geo": "1.12.0",
+        "d3-path": "1.0.9"
+      },
+      "dependencies": {
+        "d3-geo": {
+          "version": "1.12.0",
+          "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.12.0.tgz",
+          "integrity": "sha512-NalZVW+6/SpbKcnl+BCO67m8gX+nGeJdo6oGL9H6BRUGUL1e+AtPcP4vE4TwCQ/gl8y5KE7QvBzrLn+HsKIl+w==",
+          "requires": {
+            "d3-array": "1.2.4"
+          }
+        }
+      }
+    },
+    "d3-dsv": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-1.2.0.tgz",
+      "integrity": "sha512-9yVlqvZcSOMhCYzniHE7EVUws7Fa1zgw+/EAV2BxJoG3ME19V6BQFBwI855XQDsxyOuG7NibqRMTtiF/Qup46g==",
+      "requires": {
+        "commander": "2.20.0",
+        "iconv-lite": "0.4.24",
+        "rw": "1.3.3"
+      }
+    },
     "d3-ease": {
       "version": "1.0.6",
       "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.6.tgz",
       "integrity": "sha512-SZ/lVU7LRXafqp7XtIcBdxnWl8yyLpgOmzAk0mWBI9gXNzLDx5ybZgnRbH9dN/yY5tzVBqCQ9avltSnqVwessQ=="
+    },
+    "d3-geo": {
+      "version": "1.6.4",
+      "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.6.4.tgz",
+      "integrity": "sha1-8g4eRhyxhF9ai+Vatvh2VCp+MZk=",
+      "requires": {
+        "d3-array": "1.2.4"
+      }
+    },
+    "d3-geo-projection": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/d3-geo-projection/-/d3-geo-projection-2.1.2.tgz",
+      "integrity": "sha1-ffjh6dBG1jHGUJ9+UxNX1K3CSqM=",
+      "requires": {
+        "commander": "2.20.0",
+        "d3-array": "1.2.4",
+        "d3-geo": "1.6.4"
+      }
+    },
+    "d3-hexjson": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/d3-hexjson/-/d3-hexjson-1.1.0.tgz",
+      "integrity": "sha512-fHXGMnA1iYBg0Kw5jqSm9kZDRyw4Mq74AzJzUM/FiCDy9a47xM5qj2+ofTaZbeku9tHsRtoujolHiqmD3s3EHA==",
+      "requires": {
+        "d3-array": "1.2.4"
+      }
+    },
+    "d3-hierarchy": {
+      "version": "1.1.9",
+      "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-1.1.9.tgz",
+      "integrity": "sha512-j8tPxlqh1srJHAtxfvOUwKNYJkQuBFdM1+JAUfq6xqH5eAqf93L7oG1NVqDa4CpFZNvnNKtCYEUC8KY9yEn9lQ=="
     },
     "d3-interpolate": {
       "version": "1.4.0",
@@ -4431,15 +4537,52 @@
         "d3-color": "1.4.0"
       }
     },
+    "d3-path": {
+      "version": "1.0.9",
+      "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz",
+      "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg=="
+    },
     "d3-regression": {
       "version": "1.3.4",
       "resolved": "https://registry.npmjs.org/d3-regression/-/d3-regression-1.3.4.tgz",
       "integrity": "sha512-o5nwONeooEfy+L98Ej+WPccb6LgLKtsnXLuWzXb8Ta1mN95Jy0Aw9X2TxV+S+OW+NcrBfEjxSURoSlQfVAEkrg=="
     },
+    "d3-sankey": {
+      "version": "0.9.1",
+      "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.9.1.tgz",
+      "integrity": "sha512-nnRkDaUMjBdeuGg+kWGdA+tjG1AVTnJ+Ykw7ff7CZHVI17Hm5sy8n0UXykVffn13aNHwK5wPOdOt1gS1ZEaF+A==",
+      "requires": {
+        "d3-array": "1.2.4",
+        "d3-collection": "1.0.7",
+        "d3-shape": "1.3.7"
+      }
+    },
+    "d3-shape": {
+      "version": "1.3.7",
+      "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz",
+      "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==",
+      "requires": {
+        "d3-path": "1.0.9"
+      }
+    },
     "d3-timer": {
       "version": "1.0.10",
       "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.10.tgz",
       "integrity": "sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw=="
+    },
+    "d3-voronoi": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.4.tgz",
+      "integrity": "sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg=="
+    },
+    "dagre": {
+      "version": "0.8.5",
+      "resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.5.tgz",
+      "integrity": "sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==",
+      "requires": {
+        "graphlib": "2.1.8",
+        "lodash": "4.17.15"
+      }
     },
     "damerau-levenshtein": {
       "version": "1.0.5",
@@ -8104,6 +8247,14 @@
       "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz",
       "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q=="
     },
+    "graphlib": {
+      "version": "2.1.8",
+      "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz",
+      "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==",
+      "requires": {
+        "lodash": "4.17.15"
+      }
+    },
     "growly": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
@@ -11656,6 +11807,11 @@
         "json-parse-better-errors": "1.0.2"
       }
     },
+    "parse-svg-path": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/parse-svg-path/-/parse-svg-path-0.1.2.tgz",
+      "integrity": "sha1-en7A0esG+lMlx9PgCbhZoJtdSes="
+    },
     "parse5": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz",
@@ -11857,6 +12013,16 @@
       "integrity": "sha512-jd9olUr9D7do+RN8Wspzhpxhgp1n6Vd0NtQ4SFkmIACZoEL1nkyAdW9Ygrinjec0vgDcWjscFQQ1gDW8rsfKTg==",
       "requires": {
         "ts-pnp": "1.1.2"
+      }
+    },
+    "point-at-length": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/point-at-length/-/point-at-length-1.1.0.tgz",
+      "integrity": "sha1-CtcuvQmA1/WhqxIpbAVfnrazDlc=",
+      "requires": {
+        "abs-svg-path": "0.1.1",
+        "isarray": "0.0.1",
+        "parse-svg-path": "0.1.2"
       }
     },
     "portfinder": {
@@ -14112,6 +14278,11 @@
         }
       }
     },
+    "regression": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/regression/-/regression-2.0.1.tgz",
+      "integrity": "sha1-jSnD6CJKEIUMNeM36FqLL6w7DIc="
+    },
     "relateurl": {
       "version": "0.2.7",
       "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
@@ -14413,6 +14584,11 @@
       "requires": {
         "aproba": "1.2.0"
       }
+    },
+    "rw": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz",
+      "integrity": "sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q="
     },
     "rxjs": {
       "version": "6.5.3",
@@ -14989,6 +15165,11 @@
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
       "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
+    },
+    "simple-statistics": {
+      "version": "6.1.1",
+      "resolved": "https://registry.npmjs.org/simple-statistics/-/simple-statistics-6.1.1.tgz",
+      "integrity": "sha512-zGwn0DDRa9Zel4H4n2pjTFIyGoAGpnpjrGIctreCxj5XWrcx9v7Xy7270FkC967WMmcvuc8ZU7m0ZG+hGN7gAA=="
     },
     "simple-swizzle": {
       "version": "0.2.2",
@@ -15919,6 +16100,14 @@
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
       "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
+    },
+    "topojson-client": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/topojson-client/-/topojson-client-3.1.0.tgz",
+      "integrity": "sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw==",
+      "requires": {
+        "commander": "2.20.0"
+      }
     },
     "tough-cookie": {
       "version": "2.4.3",
@@ -16952,6 +17141,11 @@
         "string-width": "1.0.2"
       }
     },
+    "wolfy87-eventemitter": {
+      "version": "5.2.9",
+      "resolved": "https://registry.npmjs.org/wolfy87-eventemitter/-/wolfy87-eventemitter-5.2.9.tgz",
+      "integrity": "sha512-P+6vtWyuDw+MB01X7UeF8TaHBvbCovf4HPEMF/SV7BdDc1SMTiBy13SRD71lQh4ExFTG1d/WNzDGDCyOKSMblw=="
+    },
     "wordwrap": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
diff --git a/package.json b/package.json
index 781b4e4..c53b0cd 100644
--- a/package.json
+++ b/package.json
@@ -3,6 +3,7 @@
   "version": "0.1.0",
   "private": true,
   "dependencies": {
+    "@antv/data-set": "^0.11.4",
     "@antv/g2": "^4.0.7",
     "@antv/g2plot": "^1.0.3",
     "@babel/core": "7.5.5",
diff --git a/src/assets/css/main.scss b/src/assets/css/main.scss
index 1554c1c..0cad06f 100644
--- a/src/assets/css/main.scss
+++ b/src/assets/css/main.scss
@@ -175,6 +175,27 @@
   z-index: 1090!important;
 }
 
+.mk-normal-dropdown {
+  .ant-dropdown-menu {
+    max-height: 250px;
+    overflow-y: auto;
+  }
+  .ant-dropdown-menu::-webkit-scrollbar {
+    width: 7px;
+  }
+  .ant-dropdown-menu::-webkit-scrollbar-thumb {
+    border-radius: 5px;
+    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
+    background: rgba(0, 0, 0, 0.13);
+  }
+  .ant-dropdown-menu::-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-modal.ant-modal-confirm {
   top: 38vh;
@@ -247,4 +268,8 @@
     border: 1px solid rgba(0, 0, 0, 0.07);
     background: rgba(0, 0, 0, 0);
   }
+}
+
+.ant-drawer {
+  z-index: 1080!important;
 }
\ No newline at end of file
diff --git a/src/assets/img/A_aFXQS7yyDyUAAAAAAAAAAABkARQnAQ.png b/src/assets/img/A_aFXQS7yyDyUAAAAAAAAAAABkARQnAQ.png
new file mode 100644
index 0000000..4b06a07
--- /dev/null
+++ b/src/assets/img/A_aFXQS7yyDyUAAAAAAAAAAABkARQnAQ.png
Binary files differ
diff --git a/src/assets/img/A_qpizTrPVB-IAAAAAAAAAAABkARQnAQ.png b/src/assets/img/A_qpizTrPVB-IAAAAAAAAAAABkARQnAQ.png
new file mode 100644
index 0000000..15e708a
--- /dev/null
+++ b/src/assets/img/A_qpizTrPVB-IAAAAAAAAAAABkARQnAQ.png
Binary files differ
diff --git a/src/assets/img/bar1.png b/src/assets/img/bar1.png
new file mode 100644
index 0000000..977b4ec
--- /dev/null
+++ b/src/assets/img/bar1.png
Binary files differ
diff --git a/src/assets/img/bar2.png b/src/assets/img/bar2.png
new file mode 100644
index 0000000..0a9d95e
--- /dev/null
+++ b/src/assets/img/bar2.png
Binary files differ
diff --git a/src/assets/img/bar3.png b/src/assets/img/bar3.png
new file mode 100644
index 0000000..0766655
--- /dev/null
+++ b/src/assets/img/bar3.png
Binary files differ
diff --git a/src/assets/img/bar4.png b/src/assets/img/bar4.png
new file mode 100644
index 0000000..bea9459
--- /dev/null
+++ b/src/assets/img/bar4.png
Binary files differ
diff --git a/src/assets/img/line1.png b/src/assets/img/line1.png
new file mode 100644
index 0000000..55a628e
--- /dev/null
+++ b/src/assets/img/line1.png
Binary files differ
diff --git a/src/assets/img/line2.png b/src/assets/img/line2.png
new file mode 100644
index 0000000..c44f1d6
--- /dev/null
+++ b/src/assets/img/line2.png
Binary files differ
diff --git a/src/assets/img/line3.png b/src/assets/img/line3.png
new file mode 100644
index 0000000..b3a44b0
--- /dev/null
+++ b/src/assets/img/line3.png
Binary files differ
diff --git a/src/assets/img/line4.png b/src/assets/img/line4.png
new file mode 100644
index 0000000..cebfa94
--- /dev/null
+++ b/src/assets/img/line4.png
Binary files differ
diff --git a/src/assets/img/pie1.png b/src/assets/img/pie1.png
new file mode 100644
index 0000000..83c04c3
--- /dev/null
+++ b/src/assets/img/pie1.png
Binary files differ
diff --git a/src/assets/img/pie2.png b/src/assets/img/pie2.png
new file mode 100644
index 0000000..4584a7e
--- /dev/null
+++ b/src/assets/img/pie2.png
Binary files differ
diff --git "a/src/assets/img/\345\276\256\344\277\241\345\233\276\347\211\207_20200426165043.png" "b/src/assets/img/\345\276\256\344\277\241\345\233\276\347\211\207_20200426165043.png"
new file mode 100644
index 0000000..92d46cf
--- /dev/null
+++ "b/src/assets/img/\345\276\256\344\277\241\345\233\276\347\211\207_20200426165043.png"
Binary files differ
diff --git a/src/components/dragelement/index.jsx b/src/components/dragelement/index.jsx
index 4af0471..203eb77 100644
--- a/src/components/dragelement/index.jsx
+++ b/src/components/dragelement/index.jsx
@@ -65,7 +65,7 @@
         <Icon type="plus" />
       </div>
       <Button type="primary" onClick={thawmenu}>{dict['header.thawmenu']}</Button>
-      <Button type="primary" onClick={confirm}>{dict['header.confirm']}</Button>
+      <Button type="primary" onClick={confirm}>{dict['model.confirm']}</Button>
       <Button onClick={cancel}>{dict['header.close']}</Button>
     </div>
   )
diff --git a/src/components/sidemenu/config.js b/src/components/sidemenu/config.jsx
similarity index 100%
rename from src/components/sidemenu/config.js
rename to src/components/sidemenu/config.jsx
diff --git a/src/components/sidemenu/index.jsx b/src/components/sidemenu/index.jsx
index b4c157b..fe497e4 100644
--- a/src/components/sidemenu/index.jsx
+++ b/src/components/sidemenu/index.jsx
@@ -7,7 +7,7 @@
 
 import asyncComponent from '@/utils/asyncComponent'
 import { modifyTabview, resetEditLevel } from '@/store/action'
-import { SySMenuList } from './config.js'
+import { SySMenuList } from './config'
 import options from '@/store/options.js'
 import zhCN from '@/locales/zh-CN/header.js'
 import enUS from '@/locales/en-US/header.js'
diff --git a/src/locales/en-US/comtable.js b/src/locales/en-US/model.js
similarity index 84%
rename from src/locales/en-US/comtable.js
rename to src/locales/en-US/model.js
index 7a12562..db9719b 100644
--- a/src/locales/en-US/comtable.js
+++ b/src/locales/en-US/model.js
@@ -1,9 +1,10 @@
 export default {
-  'header.confirm': 'Ok',
+  'model.confirm': 'Ok',
   'header.submit': 'Submit',
-  'header.delete': 'Delete',
+  'model.delete': 'Delete',
   'header.cancel': 'Cancel',
-  'header.edit': 'Edit',
+  'model.edit': 'Edit',
+  'model.copy': 'Copy',
   'header.return': 'Back',
   'header.save': 'Save',
   'header.notsave': 'Do not save',
@@ -65,6 +66,7 @@
   'header.form.column.itemsUnit': 'Items',
   'header.form.column.action': 'Action',
   'header.form.name': 'Name',
+  'header.form.title': 'Title',
   'header.form.field': 'Field',
   'header.form.field.placeholder': '璇疯緭鍏ュ瓧娈靛悕',
   'header.form.innerFunc': 'Internal function',
@@ -228,16 +230,22 @@
   'header.form.clickscale': '鐐瑰嚮缂╂斁',
   'header.form.easyCode': '鍔╄鐮�',
   'header.modal.form.edit': '琛ㄥ崟-缂栬緫',
-  'header.modal.search.edit': '鎼滅储鏉′欢-缂栬緫',
-  'header.modal.action.edit': '鎸夐挳-缂栬緫',
+  'model.searchCriteria': 'Search Criteria',
+  'model.action': '鎸夐挳',
   'header.modal.action.copy': '鎸夐挳-澶嶅埗',
   'header.modal.form.copy': '琛ㄥ崟-澶嶅埗',
   'header.modal.column.edit': '鏄剧ず鍒�-缂栬緫',
   'header.modal.colspan.edit': '鍚堝苟鍒�-缂栬緫',
   'header.modal.gridbtn.edit': '鎿嶄綔鍒�-缂栬緫',
   'header.modal.tabs.edit': '鏍囩-缂栬緫',
-  'header.modal.func.innerface': '鍐呴儴鎺ュ彛: 鍙嚜瀹氫箟鏁版嵁澶勭悊鍑芥暟锛屽嚱鏁板悕绉伴渶浠ableField绛夊瓧绗﹀紑濮嬶紱鏈缃椂浼氳皟鐢ㄧ郴缁熷嚱鏁帮紝浣跨敤绯荤粺鍑芥暟闇�瀹屽杽鏁版嵁婧愬強鎿嶄綔绫诲瀷;',
-  'header.modal.func.outface': '澶栭儴鎺ュ彛: 鍙嚜瀹氫箟鏁版嵁澶勭悊鍑芥暟锛屾彁浜ゆ暟鎹粡杩囧唴閮ㄥ嚱鏁板鐞嗗悗锛屼紶鍏ュ閮ㄦ帴鍙o紝鏈缃椂锛屾暟鎹細鐩存帴浼犲叆澶栭儴鎺ュ彛銆�',
+  'model.field.exist': '瀛楁宸插瓨鍦�',
+  'model.name.exist': '鍚嶇О宸插瓨鍦�',
   'form.required.input': 'Please enter the ',
-  'form.required.select': '璇烽�夋嫨'
+  'form.required.select': '璇烽�夋嫨',
+  'model.tooltip.table.guide': '姝ゅ鍙互娣诲姞椤甸潰閰嶇疆鐩稿叧鐨勫父鐢ㄨ〃锛屽彲閫氳繃宸ュ叿鏍忎腑鐨勬坊鍔犳寜閽紝鍙壒閲忔坊鍔犺〃鏍肩浉鍏冲瓧娈点��',
+  'model.tooltip.search.guide': '鍦ㄥ乏渚у伐鍏锋爮銆婃悳绱€�嬩腑锛岄�夋嫨瀵瑰簲鎼滅储妗嗘嫋鑷虫澶勬坊鍔狅紱鎴栫偣鍑绘寜閽�婃坊鍔犳悳绱㈡潯浠躲�嬫壒閲忔坊鍔狅紝閫夋嫨鎵归噺娣诲姞鏃讹紝闇�鎻愬墠閫夋嫨浣跨敤琛ㄣ��',
+  'model.tooltip.action.guide': '鍦ㄥ乏渚у伐鍏锋爮銆婃寜閽�嬩腑锛岄�夋嫨瀵瑰簲绫诲瀷鐨勬寜閽嫋鑷虫澶勬坊鍔狅紝濡傞�夋嫨鎸夐挳绫诲瀷涓鸿〃鍗曘�佹柊鏍囩椤电瓑鍚湁閰嶇疆椤甸潰鐨勬寜閽紝鍙湪宸︿晶宸ュ叿鏍�-鎸夐挳-鍙厤缃寜閽锛岀偣鍑绘寜閽畬鎴愮浉鍏抽厤缃�傛敞锛氬綋璁剧疆鎸夐挳鏄剧ず浣嶇疆涓鸿〃鏍兼椂锛屾樉绀哄垪浼氬鍔犳搷浣滃垪銆�',
+  'model.tooltip.column.guide': '鍦ㄥ乏渚у伐鍏锋爮銆婃樉绀哄垪銆嬩腑锛岄�夋嫨瀵瑰簲绫诲瀷鐨勬樉绀哄垪鎷栬嚦姝ゅ娣诲姞锛涙垨鐐瑰嚮銆婃坊鍔犳樉绀哄垪銆嬫寜閽壒閲忔坊鍔狅紝閫夋嫨鎵归噺娣诲姞鏃讹紝闇�鎻愬墠閫夋嫨浣跨敤琛ㄣ�傛敞锛氭坊鍔犲悎骞跺垪鏃讹紝闇�璁剧疆鍙�夊垪銆�',
+  'model.tooltip.func.innerface': '鍐呴儴鎺ュ彛: 鍙嚜瀹氫箟鏁版嵁澶勭悊鍑芥暟锛屽嚱鏁板悕绉伴渶浠ableField绛夊瓧绗﹀紑濮嬶紱鏈缃椂浼氳皟鐢ㄧ郴缁熷嚱鏁帮紝浣跨敤绯荤粺鍑芥暟闇�瀹屽杽鏁版嵁婧愬強鎿嶄綔绫诲瀷;',
+  'model.tooltip.func.outface': '澶栭儴鎺ュ彛: 鍙嚜瀹氫箟鏁版嵁澶勭悊鍑芥暟锛屾彁浜ゆ暟鎹粡杩囧唴閮ㄥ嚱鏁板鐞嗗悗锛屼紶鍏ュ閮ㄦ帴鍙o紝鏈缃椂锛屾暟鎹細鐩存帴浼犲叆澶栭儴鎺ュ彛銆�',
 }
\ No newline at end of file
diff --git a/src/locales/zh-CN/comtable.js b/src/locales/zh-CN/model.js
similarity index 84%
rename from src/locales/zh-CN/comtable.js
rename to src/locales/zh-CN/model.js
index df7f890..1360bd4 100644
--- a/src/locales/zh-CN/comtable.js
+++ b/src/locales/zh-CN/model.js
@@ -1,9 +1,10 @@
 export default {
-  'header.confirm': '纭畾',
+  'model.confirm': '纭畾',
   'header.submit': '鎻愪氦',
-  'header.delete': '鍒犻櫎',
+  'model.delete': '鍒犻櫎',
   'header.cancel': '鍙栨秷',
-  'header.edit': '缂栬緫',
+  'model.edit': '缂栬緫',
+  'model.copy': '澶嶅埗',
   'header.return': '杩斿洖',
   'header.save': '淇濆瓨',
   'header.notsave': '涓嶄繚瀛�',
@@ -65,6 +66,7 @@
   'header.form.column.itemsUnit': '椤�',
   'header.form.column.action': '鎿嶄綔',
   'header.form.name': '鍚嶇О',
+  'header.form.title': '鏍囬',
   'header.form.field': '瀛楁',
   'header.form.field.placeholder': '璇疯緭鍏ュ瓧娈靛悕',
   'header.form.innerFunc': '鍐呴儴鍑芥暟',
@@ -228,16 +230,22 @@
   'header.form.clickscale': '鐐瑰嚮缂╂斁',
   'header.form.easyCode': '鍔╄鐮�',
   'header.modal.form.edit': '琛ㄥ崟-缂栬緫',
-  'header.modal.search.edit': '鎼滅储鏉′欢-缂栬緫',
-  'header.modal.action.edit': '鎸夐挳-缂栬緫',
+  'model.searchCriteria': '鎼滅储鏉′欢',
+  'model.action': 'Button',
   'header.modal.action.copy': '鎸夐挳-澶嶅埗',
   'header.modal.form.copy': '琛ㄥ崟-澶嶅埗',
   'header.modal.column.edit': '鏄剧ず鍒�-缂栬緫',
   'header.modal.colspan.edit': '鍚堝苟鍒�-缂栬緫',
   'header.modal.gridbtn.edit': '鎿嶄綔鍒�-缂栬緫',
   'header.modal.tabs.edit': '鏍囩-缂栬緫',
-  'header.modal.func.innerface': '鍐呴儴鎺ュ彛: 鍙嚜瀹氫箟鏁版嵁澶勭悊鍑芥暟锛屽嚱鏁板悕绉伴渶浠ableField绛夊瓧绗﹀紑濮嬶紱鏈缃椂浼氳皟鐢ㄧ郴缁熷嚱鏁帮紝浣跨敤绯荤粺鍑芥暟闇�瀹屽杽鏁版嵁婧愬強鎿嶄綔绫诲瀷;',
-  'header.modal.func.outface': '澶栭儴鎺ュ彛: 鍙嚜瀹氫箟鏁版嵁澶勭悊鍑芥暟锛屾彁浜ゆ暟鎹粡杩囧唴閮ㄥ嚱鏁板鐞嗗悗锛屼紶鍏ュ閮ㄦ帴鍙o紝鏈缃椂锛屾暟鎹細鐩存帴浼犲叆澶栭儴鎺ュ彛銆�',
+  'model.field.exist': '瀛楁宸插瓨鍦�',
+  'model.name.exist': '鍚嶇О宸插瓨鍦�',
   'form.required.input': '璇疯緭鍏�',
-  'form.required.select': '璇烽�夋嫨'
+  'form.required.select': '璇烽�夋嫨',
+  'model.tooltip.table.guide': '姝ゅ鍙互娣诲姞椤甸潰閰嶇疆鐩稿叧鐨勫父鐢ㄨ〃锛屽彲閫氳繃宸ュ叿鏍忎腑鐨勬坊鍔犳寜閽紝鍙壒閲忔坊鍔犺〃鏍肩浉鍏冲瓧娈点��',
+  'model.tooltip.search.guide': '鍦ㄥ乏渚у伐鍏锋爮銆婃悳绱€�嬩腑锛岄�夋嫨瀵瑰簲鎼滅储妗嗘嫋鑷虫澶勬坊鍔狅紱鎴栫偣鍑绘寜閽�婃坊鍔犳悳绱㈡潯浠躲�嬫壒閲忔坊鍔狅紝閫夋嫨鎵归噺娣诲姞鏃讹紝闇�鎻愬墠閫夋嫨浣跨敤琛ㄣ��',
+  'model.tooltip.action.guide': '鍦ㄥ乏渚у伐鍏锋爮銆婃寜閽�嬩腑锛岄�夋嫨瀵瑰簲绫诲瀷鐨勬寜閽嫋鑷虫澶勬坊鍔狅紝濡傞�夋嫨鎸夐挳绫诲瀷涓鸿〃鍗曘�佹柊鏍囩椤电瓑鍚湁閰嶇疆椤甸潰鐨勬寜閽紝鍙湪宸︿晶宸ュ叿鏍�-鎸夐挳-鍙厤缃寜閽锛岀偣鍑绘寜閽畬鎴愮浉鍏抽厤缃�傛敞锛氬綋璁剧疆鎸夐挳鏄剧ず浣嶇疆涓鸿〃鏍兼椂锛屾樉绀哄垪浼氬鍔犳搷浣滃垪銆�',
+  'model.tooltip.column.guide': '鍦ㄥ乏渚у伐鍏锋爮銆婃樉绀哄垪銆嬩腑锛岄�夋嫨瀵瑰簲绫诲瀷鐨勬樉绀哄垪鎷栬嚦姝ゅ娣诲姞锛涙垨鐐瑰嚮銆婃坊鍔犳樉绀哄垪銆嬫寜閽壒閲忔坊鍔狅紝閫夋嫨鎵归噺娣诲姞鏃讹紝闇�鎻愬墠閫夋嫨浣跨敤琛ㄣ�傛敞锛氭坊鍔犲悎骞跺垪鏃讹紝闇�璁剧疆鍙�夊垪銆�',
+  'model.tooltip.func.innerface': '鍐呴儴鎺ュ彛: 鍙嚜瀹氫箟鏁版嵁澶勭悊鍑芥暟锛屽嚱鏁板悕绉伴渶浠ableField绛夊瓧绗﹀紑濮嬶紱鏈缃椂浼氳皟鐢ㄧ郴缁熷嚱鏁帮紝浣跨敤绯荤粺鍑芥暟闇�瀹屽杽鏁版嵁婧愬強鎿嶄綔绫诲瀷;',
+  'model.tooltip.func.outface': '澶栭儴鎺ュ彛: 鍙嚜瀹氫箟鏁版嵁澶勭悊鍑芥暟锛屾彁浜ゆ暟鎹粡杩囧唴閮ㄥ嚱鏁板鐞嗗悗锛屼紶鍏ュ閮ㄦ帴鍙o紝鏈缃椂锛屾暟鎹細鐩存帴浼犲叆澶栭儴鎺ュ彛銆�',
 }
\ No newline at end of file
diff --git a/src/tabviews/commontable/index.jsx b/src/tabviews/commontable/index.jsx
index 0f79790..9b83524 100644
--- a/src/tabviews/commontable/index.jsx
+++ b/src/tabviews/commontable/index.jsx
@@ -174,6 +174,7 @@
           }
 
           if (_curUserConfig.action[item.uuid]) {
+            delete _curUserConfig.action[item.uuid].label
             item = {...item, ..._curUserConfig.action[item.uuid]}
           }
           
@@ -283,6 +284,7 @@
       if (_curUserConfig) {
         _columns = _columns.map(item => {
           if (_curUserConfig.columns[item.uuid]) {
+            delete _curUserConfig.columns[item.uuid].label
             item = {...item, ..._curUserConfig.columns[item.uuid]}
           }
 
diff --git a/src/tabviews/subtable/index.jsx b/src/tabviews/subtable/index.jsx
index f044c02..88105fc 100644
--- a/src/tabviews/subtable/index.jsx
+++ b/src/tabviews/subtable/index.jsx
@@ -175,6 +175,7 @@
 
         config.action = config.action.map(item => {
           if (userConfig.action[item.uuid]) {
+            delete userConfig.action[item.uuid].label
             item = {...item, ...userConfig.action[item.uuid]}
           }
 
@@ -270,6 +271,7 @@
       if (userConfig) {
         _columns = _columns.map(item => {
           if (userConfig.columns[item.uuid]) {
+            delete userConfig.columns[item.uuid].label
             item = {...item, ...userConfig.columns[item.uuid]}
           }
 
diff --git a/src/tabviews/zshare/verifycard/index.jsx b/src/tabviews/zshare/verifycard/index.jsx
index 23bdd7b..9cc08f8 100644
--- a/src/tabviews/zshare/verifycard/index.jsx
+++ b/src/tabviews/zshare/verifycard/index.jsx
@@ -144,6 +144,7 @@
 
             subconfig.action = subconfig.action.map(item => {
               if (subUserConfig.action[item.uuid]) {
+                delete subUserConfig.action[item.uuid].label
                 item = {...item, ...subUserConfig.action[item.uuid]}
               }
               if (item.execMode) {
@@ -215,6 +216,7 @@
           if (subUserConfig) {
             _columns = _columns.map(item => {
               if (subUserConfig.columns[item.uuid]) {
+                delete subUserConfig.columns[item.uuid].label
                 item = {...item, ...subUserConfig.columns[item.uuid]}
               }
 
diff --git a/src/templates/comtableconfig/index.jsx b/src/templates/comtableconfig/index.jsx
index ac8f3cc..c3135c9 100644
--- a/src/templates/comtableconfig/index.jsx
+++ b/src/templates/comtableconfig/index.jsx
@@ -10,8 +10,8 @@
 import Api from '@/api'
 import Utils from '@/utils/utils.js'
 import options from '@/store/options.js'
-import zhCN from '@/locales/zh-CN/comtable.js'
-import enUS from '@/locales/en-US/comtable.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
 import { getSearchForm, getActionForm, getColumnForm } from '@/templates/zshare/formconfig'
 import { queryTableSql } from '@/utils/option.js'
 
@@ -455,8 +455,8 @@
   handleAction = (card, type) => {
     let ableField = this.props.permFuncField.join(', ')
     let functip = <div>
-      <p style={{marginBottom: '5px'}}>{this.state.dict['header.modal.func.innerface'].replace('@ableField', ableField)}</p>
-      <p>{this.state.dict['header.modal.func.outface']}</p>
+      <p style={{marginBottom: '5px'}}>{this.state.dict['model.tooltip.func.innerface'].replace('@ableField', ableField)}</p>
+      <p>{this.state.dict['model.tooltip.func.outface']}</p>
     </div>
 
     this.setState({
@@ -1272,22 +1272,13 @@
 
     this.menuformRef.handleConfirm().then(res => {
       this.actionFormRef.handleConfirm().then(result => {
-        if (!['pop', 'exec', 'prompt'].includes(result.OpenType) || result.funcType || result.intertype !== 'inner' || result.innerFunc ) {
-          notification.warning({
-            top: 92,
-            message: '鎵撳紑鏂瑰紡涓� 寮圭獥锛堣〃鍗曪級銆佹彁绀烘鎴栫洿鎺ユ墽琛岋紝涓斾娇鐢ㄧ郴缁熷嚱鏁版椂锛屾墠鍙互鍒涘缓鎺ュ彛锛�',
-            duration: 5
-          })
-          return
-        }
-
         let _menu = {
           type: 'main',
           MenuID: menu.MenuID,
           menuName: res.menuName,
           menuNo: res.menuNo
         }
-        
+
         this.refs.btnCreatInterface.triggerInInterface(result, config, _menu)
       })
     })
@@ -1330,7 +1321,7 @@
 
     confirm({
       content: `纭畾鍒犻櫎<<${element.card.label}>>鍚楋紵`,
-      okText: this.state.dict['header.confirm'],
+      okText: this.state.dict['model.confirm'],
       cancelText: this.state.dict['header.cancel'],
       onOk() {
         let _config = null
@@ -2110,7 +2101,7 @@
     if (config.isAdd) {
       confirm({
         content: '鑿滃崟灏氭湭鎻愪氦锛岀‘瀹氭斁寮冧繚瀛樺悧锛�',
-        okText: this.state.dict['header.confirm'],
+        okText: this.state.dict['model.confirm'],
         cancelText: this.state.dict['header.cancel'],
         onOk() {
           _this.props.handleView()
@@ -2209,25 +2200,6 @@
       })
     }
 
-    const textmatch = { // 閫夋嫨text鏃跺尮閰嶈鍒�
-      text: 'like',
-      number: 'like',
-      datetime: 'like',
-      date: 'like'
-    }
-    const selectmatch = { // 閫夋嫨select鏃跺尮閰嶈鍒�
-      text: '=',
-      number: '=',
-      datetime: '=',
-      date: '='
-    }
-    const datematch = { // 閫夋嫨dateRange鏃跺尮閰嶈鍒�
-      text: 'between',
-      number: 'between',
-      datetime: 'between',
-      date: 'between'
-    }
-
     // 鑾峰彇宸查�夊瓧娈甸泦鍚�
     let cards = this.refs.searchcard.state.selectCards
 
@@ -2255,12 +2227,12 @@
 
           if (cell.type !== item.type) { // 鏁版嵁绫诲瀷淇敼
             if (cell.type === 'select') {
-              item.match = selectmatch[cell.datatype]
+              item.match = '='
             } else if (cell.type === 'daterange') {
-              item.match = datematch[cell.datatype]
+              item.match = 'between'
             } else {
               cell.type = 'text'
-              item.match = textmatch[cell.datatype]
+              item.match = 'like'
             }
             
             item.type = cell.type
@@ -2277,11 +2249,11 @@
       _columns.forEach(item => {
         let _match = ''
         if (item.type === 'select') {
-          _match = selectmatch[item.datatype]
+          _match = '='
         } else if (item.type === 'daterange') {
-          _match = datematch[item.datatype]
+          _match = 'between'
         } else {
-          _match = textmatch[item.datatype]
+          _match = 'like'
         }
 
         let newcard = {
@@ -2734,7 +2706,7 @@
 
     confirm({
       content: `纭畾鏂板缓鏍囩缁勫悧锛焋,
-      okText: this.state.dict['header.confirm'],
+      okText: this.state.dict['model.confirm'],
       cancelText: this.state.dict['header.cancel'],
       onOk() {
         let newgroup = 'tabs' + Utils.getuuid()
@@ -2759,7 +2731,7 @@
 
     confirm({
       content: `纭畾鍒犻櫎鏍囩缁勫悧锛焋,
-      okText: this.state.dict['header.confirm'],
+      okText: this.state.dict['model.confirm'],
       cancelText: this.state.dict['header.cancel'],
       onOk() {
 
@@ -3119,7 +3091,7 @@
             hasbtncrtinter ? <CreateInterface key="interface" dict={this.state.dict} ref="btnCreatInterface" trigger={this.btnCreatInterface}/> : null,
             modaltype === 'actionEdit' ? <CreateFunc key="create" dict={this.state.dict} ref="btnCreatFunc" trigger={this.creatFunc}/> : null,
             <Button key="cancel" onClick={this.editModalCancel}>{this.state.dict['header.cancel']}</Button>,
-            <Button key="confirm" type="primary" onClick={this.handleSubmit}>{this.state.dict['header.confirm']}</Button>
+            <Button key="confirm" type="primary" onClick={this.handleSubmit}>{this.state.dict['model.confirm']}</Button>
           ]}
           destroyOnClose
         >
@@ -3210,7 +3182,7 @@
         {/* 鏍规嵁瀛楁鍚嶆坊鍔犳樉绀哄垪鍙婃悳绱㈡潯浠� */}
         <Modal
           wrapClassName="common-table-fields-modal"
-          title={this.state.dict['header.edit']}
+          title={this.state.dict['model.edit']}
           visible={this.state.tableVisible}
           width={'65vw'}
           maskClosable={false}
@@ -3279,7 +3251,7 @@
         </Modal>
         {/* 璁剧疆鍏ㄥ眬閰嶇疆鍙婂垪琛ㄦ暟鎹簮 */}
         <Modal
-          title={this.state.dict['header.edit']}
+          title={this.state.dict['model.edit']}
           visible={this.state.settingVisible}
           width={750}
           maskClosable={false}
@@ -3292,7 +3264,7 @@
             <CreateInterface key="interface" dict={this.state.dict} ref="tableCreatInterface" trigger={this.tableCreatInterface}/>,
             <CreateFunc key="create" dict={this.state.dict} ref="tableCreatFunc" trigger={this.tableCreatFunc}/>,
             <Button key="cancel" onClick={() => { this.setState({ settingVisible: false }) }}>{this.state.dict['header.cancel']}</Button>,
-            <Button key="confirm" type="primary" loading={this.state.sqlVerifing} onClick={this.settingSave}>{this.state.dict['header.confirm']}</Button>
+            <Button key="confirm" type="primary" loading={this.state.sqlVerifing} onClick={this.settingSave}>{this.state.dict['model.confirm']}</Button>
           ]}
           destroyOnClose
         >
diff --git a/src/templates/comtableconfig/source.jsx b/src/templates/comtableconfig/source.jsx
index 8fc542e..06db883 100644
--- a/src/templates/comtableconfig/source.jsx
+++ b/src/templates/comtableconfig/source.jsx
@@ -1,6 +1,6 @@
 import Utils from '@/utils/utils.js'
-import zhCN from '@/locales/zh-CN/comtable.js'
-import enUS from '@/locales/en-US/comtable.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
 
 const CommonDict = (!localStorage.getItem('lang') || localStorage.getItem('lang') === 'zh-CN') ? zhCN : enUS
 
diff --git a/src/templates/formtabconfig/index.jsx b/src/templates/formtabconfig/index.jsx
index dcc9b60..5cc4586 100644
--- a/src/templates/formtabconfig/index.jsx
+++ b/src/templates/formtabconfig/index.jsx
@@ -8,8 +8,8 @@
 import { Button, Card, Modal, Collapse, notification, Spin, Select, List, Icon, Empty, Switch, Tooltip } from 'antd'
 
 import Api from '@/api'
-import zhCN from '@/locales/zh-CN/comtable.js'
-import enUS from '@/locales/en-US/comtable.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
 import Utils from '@/utils/utils.js'
 import { getModalForm, getActionForm } from '@/templates/zshare/formconfig'
 import { queryTableSql } from '@/utils/option.js'
@@ -498,8 +498,8 @@
   handleAction = (card) => {
     let ableField = this.props.permFuncField.join(', ')
     let functip = <div>
-      <p style={{marginBottom: '5px'}}>{this.state.dict['header.modal.func.innerface'].replace('@ableField', ableField)}</p>
-      <p>{this.state.dict['header.modal.func.outface']}</p>
+      <p style={{marginBottom: '5px'}}>{this.state.dict['model.tooltip.func.innerface'].replace('@ableField', ableField)}</p>
+      <p>{this.state.dict['model.tooltip.func.outface']}</p>
     </div>
 
     this.setState({
@@ -953,7 +953,7 @@
     let _this = this
     confirm({
       content: `纭畾鍒犻櫎<<${element.card.label}>>鍚楋紵`,
-      okText: this.state.dict['header.confirm'],
+      okText: this.state.dict['model.confirm'],
       cancelText: this.state.dict['header.cancel'],
       onOk() {
         let _config = JSON.parse(JSON.stringify(_this.state.config))
@@ -1439,7 +1439,7 @@
     if (config.isAdd) {
       confirm({
         content: '鎸夐挳閰嶇疆灏氭湭鎻愪氦锛岀‘瀹氭斁寮冧繚瀛樺悧锛�',
-        okText: this.state.dict['header.confirm'],
+        okText: this.state.dict['model.confirm'],
         cancelText: this.state.dict['header.cancel'],
         onOk() {
           _this.handleViewBack()
@@ -1860,7 +1860,7 @@
 
     confirm({
       content: `纭畾鏂板缓鏍囩缁勫悧锛焋,
-      okText: this.state.dict['header.confirm'],
+      okText: this.state.dict['model.confirm'],
       cancelText: this.state.dict['header.cancel'],
       onOk() {
         let newgroup = 'tabs' + Utils.getuuid()
@@ -1882,7 +1882,7 @@
 
     confirm({
       content: `纭畾鍒犻櫎鏍囩缁勫悧锛焋,
-      okText: this.state.dict['header.confirm'],
+      okText: this.state.dict['model.confirm'],
       cancelText: this.state.dict['header.cancel'],
       onOk() {
 
@@ -1921,7 +1921,7 @@
 
     confirm({
       content: `纭畾鍒犻櫎鍒嗙粍<<${group.label}>>鍚楋紵`,
-      okText: this.state.dict['header.confirm'],
+      okText: this.state.dict['model.confirm'],
       cancelText: this.state.dict['header.cancel'],
       onOk() {
         let groups = config.groups.filter(item => !(item.uuid === group.uuid))
@@ -2245,7 +2245,7 @@
         </Modal>
         {/* 缂栬緫鎸夐挳锛氬鍒躲�佺紪杈� */}
         <Modal
-          title={this.state.dict['header.modal.action.edit']}
+          title={this.state.dict['model.action'] + '-' + this.state.dict['model.edit']}
           visible={modaltype === 'actionEdit'}
           width={700}
           maskClosable={false}
@@ -2254,7 +2254,7 @@
             this.state.card && this.state.card.btnType !== 'cancel' ?
             <CreateFunc key="create" dict={this.state.dict} ref="btnCreatFunc" trigger={this.creatFunc}/> : null,
             <Button key="cancel" onClick={this.editModalCancel}>{this.state.dict['header.cancel']}</Button>,
-            <Button key="confirm" type="primary" onClick={this.handleSubmit}>{this.state.dict['header.confirm']}</Button>
+            <Button key="confirm" type="primary" onClick={this.handleSubmit}>{this.state.dict['model.confirm']}</Button>
           ]}
           destroyOnClose
         >
@@ -2290,7 +2290,7 @@
         {/* 鏍规嵁瀛楁鍚嶆坊鍔犳樉绀哄垪鍙婃悳绱㈡潯浠� */}
         <Modal
           wrapClassName="common-table-fields-modal"
-          title={this.state.dict['header.edit']}
+          title={this.state.dict['model.edit']}
           visible={this.state.tableVisible}
           width={'65vw'}
           maskClosable={false}
@@ -2335,7 +2335,7 @@
         </Modal>
         {/* 璁剧疆鍏ㄥ眬閰嶇疆鍙婂垪琛ㄦ暟鎹簮 */}
         <Modal
-          title={this.state.dict['header.edit']}
+          title={this.state.dict['model.edit']}
           visible={this.state.settingVisible}
           width={700}
           maskClosable={false}
@@ -2347,7 +2347,7 @@
           footer={[
             <CreateFunc key="create" dict={this.state.dict} ref="tableCreatFunc" trigger={this.tableCreatFunc}/>,
             <Button key="cancel" onClick={() => { this.setState({ settingVisible: false }) }}>{this.state.dict['header.cancel']}</Button>,
-            <Button key="confirm" type="primary" loading={this.state.sqlVerifing} onClick={this.settingSave}>{this.state.dict['header.confirm']}</Button>
+            <Button key="confirm" type="primary" loading={this.state.sqlVerifing} onClick={this.settingSave}>{this.state.dict['model.confirm']}</Button>
           ]}
           destroyOnClose
         >
diff --git a/src/templates/formtabconfig/source.jsx b/src/templates/formtabconfig/source.jsx
index 7b7e8b4..962016e 100644
--- a/src/templates/formtabconfig/source.jsx
+++ b/src/templates/formtabconfig/source.jsx
@@ -1,6 +1,6 @@
 import Utils from '@/utils/utils.js'
-import zhCN from '@/locales/zh-CN/comtable.js'
-import enUS from '@/locales/en-US/comtable.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
 
 const CommonDict = (!localStorage.getItem('lang') || localStorage.getItem('lang') === 'zh-CN') ? zhCN : enUS
 
diff --git a/src/templates/modalconfig/index.jsx b/src/templates/modalconfig/index.jsx
index 1557bfb..b8b88f2 100644
--- a/src/templates/modalconfig/index.jsx
+++ b/src/templates/modalconfig/index.jsx
@@ -8,9 +8,9 @@
 import { Button, Card, Modal, Collapse, notification, Select, List, Icon, Empty } from 'antd'
 
 import Api from '@/api'
-import zhCN from '@/locales/zh-CN/comtable.js'
 import Utils from '@/utils/utils.js'
-import enUS from '@/locales/en-US/comtable.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
 import { getModalForm } from '@/templates/zshare/formconfig'
 import { queryTableSql } from '@/utils/option.js'
 
@@ -689,7 +689,7 @@
 
     confirm({
       content: `纭畾鍒犻櫎<<${card.label}>>鍚楋紵`,
-      okText: this.state.dict['header.confirm'],
+      okText: this.state.dict['model.confirm'],
       cancelText: this.state.dict['header.cancel'],
       onOk() {
         let _config = JSON.parse(JSON.stringify(_this.state.config))
@@ -794,7 +794,7 @@
     if (isOrigin) {
       confirm({
         content: '灏氭湭鎻愪氦锛岀‘瀹氭斁寮冧繚瀛樺悧锛�',
-        okText: this.state.dict['header.confirm'],
+        okText: this.state.dict['model.confirm'],
         cancelText: this.state.dict['header.cancel'],
         onOk() {
           _this.handleViewBack()
@@ -1110,7 +1110,7 @@
 
     confirm({
       content: `纭畾鍒犻櫎鍒嗙粍<<${group.label}>>鍚楋紵`,
-      okText: this.state.dict['header.confirm'],
+      okText: this.state.dict['model.confirm'],
       cancelText: this.state.dict['header.cancel'],
       onOk() {
         let _config = JSON.parse(JSON.stringify(_this.state.config))
@@ -1364,7 +1364,7 @@
                       <span>{this.state.dict['header.cancel']}</span>
                     </button>
                     <button type="button" className="ant-btn ant-btn-primary">
-                      <span>{this.state.dict['header.confirm']}</span>
+                      <span>{this.state.dict['model.confirm']}</span>
                     </button>
                   </div>
                   <div className="action-mask"></div>
@@ -1374,7 +1374,7 @@
           </div>
         </DndProvider>
         <Modal
-          title={this.state.modalType !== 'copy' ? this.state.dict['header.edit'] : this.state.dict['header.modal.form.copy']}
+          title={this.state.modalType !== 'copy' ? this.state.dict['model.edit'] : this.state.dict['header.modal.form.copy']}
           visible={this.state.visible}
           width={700}
           onCancel={this.editModalCancel}
@@ -1393,7 +1393,7 @@
         </Modal>
         <Modal
           wrapClassName="modal-fields"
-          title={this.state.dict['header.edit']}
+          title={this.state.dict['model.edit']}
           visible={this.state.tableVisible}
           width={'65vw'}
           maskClosable={false}
@@ -1411,7 +1411,7 @@
           }
         </Modal>
         <Modal
-          title={this.state.dict['header.edit']}
+          title={this.state.dict['model.edit']}
           visible={this.state.settingVisible}
           width={700}
           maskClosable={false}
diff --git a/src/templates/modalconfig/source.jsx b/src/templates/modalconfig/source.jsx
index c340150..8c4276e 100644
--- a/src/templates/modalconfig/source.jsx
+++ b/src/templates/modalconfig/source.jsx
@@ -1,6 +1,6 @@
 import Utils from '@/utils/utils.js'
-import zhCN from '@/locales/zh-CN/comtable.js'
-import enUS from '@/locales/en-US/comtable.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
 
 const CommonDict = (!localStorage.getItem('lang') || localStorage.getItem('lang') === 'zh-CN') ? zhCN : enUS
 
diff --git a/src/templates/sharecomponent/actioncomponent/actionform/index.jsx b/src/templates/sharecomponent/actioncomponent/actionform/index.jsx
new file mode 100644
index 0000000..5bb6f79
--- /dev/null
+++ b/src/templates/sharecomponent/actioncomponent/actionform/index.jsx
@@ -0,0 +1,657 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Input, Select, Icon, Radio, notification, Tooltip, InputNumber } from 'antd'
+import { btnIcons, btnClasses, formRule } from '@/utils/option.js'
+import Utils from '@/utils/utils.js'
+import './index.scss'
+
+const { TextArea } = Input
+
+class MainSearch extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,      // 瀛楀吀椤�
+    setting: PropTypes.object,   // 椤甸潰璁剧疆
+    formlist: PropTypes.any,     // 琛ㄥ崟淇℃伅
+    card: PropTypes.any,         // 鎸夐挳淇℃伅
+    tabs: PropTypes.array,       // 鎵�鏈夋爣绛鹃〉
+    inputSubmit: PropTypes.any   // 鍥炶溅鎻愪氦浜嬩欢
+  }
+
+  state = {
+    formlist: null,  // 琛ㄥ崟淇℃伅
+    openType: null,  // 鎵撳紑鏂瑰紡
+    interType: null, // 鎺ュ彛绫诲瀷锛氬唴閮ㄣ�佸閮�
+    funcType: null,  // 鍔熻兘绫诲瀷
+    position: null,  // 鎸夐挳浣嶇疆
+    reqOptionSgl: [{
+      value: 'requiredSgl',
+      text: this.props.dict['header.form.requiredSgl']
+    }],
+    reqOptions: [{
+      value: 'notRequired',
+      text: this.props.dict['header.form.notRequired']
+    }, {
+      value: 'requiredSgl',
+      text: this.props.dict['header.form.requiredSgl']
+    }],
+    reqOptionsMutil: [{
+      value: 'notRequired',
+      text: this.props.dict['header.form.notRequired']
+    }, {
+      value: 'requiredSgl',
+      text: this.props.dict['header.form.requiredSgl']
+    }, {
+      value: 'required',
+      text: this.props.dict['header.form.required']
+    }, {
+      value: 'requiredOnce',
+      text: this.props.dict['header.form.requiredOnce']
+    }],
+    insertUpdateOptions: [{
+      value: '',
+      text: this.props.dict['header.form.empty']
+    }, {
+      value: 'insert',
+      text: this.props.dict['header.form.action.insert']
+    }, {
+      value: 'update',
+      text: this.props.dict['header.form.action.update']
+    }],
+    deleteOptions: [{
+      value: '',
+      text: this.props.dict['header.form.empty']
+    }, {
+      value: 'LogicDelete',
+      text: this.props.dict['header.form.action.LogicDelete']
+    }, {
+      value: 'delete',
+      text: this.props.dict['header.form.action.delete']
+    }, {
+      value: 'custom',
+      text: this.props.dict['header.form.custom']
+    }]
+  }
+
+  
+  UNSAFE_componentWillMount () {
+    let _opentype = ''   // 鎵撳紑鏂瑰紡
+    let _intertype = ''  // 鎺ュ彛绫诲瀷
+    let _position = ''   // 鎸夐挳浣嶇疆
+    let _tabType = ''    // 鎸夐挳涓哄脊绐楋紙鏍囩锛夋椂锛屾爣绛剧殑绫诲瀷
+    let _funcType = ''   // 鍔熻兘鎸夐挳绫诲瀷
+    let _options = null  // 閫夐」鍒楄〃
+
+    this.props.formlist.forEach(form => {
+      if (form.key === 'OpenType') {
+        if (this.props.card.execMode) { // 杞崲鎵撳嵃鏃舵墦寮�鏂瑰紡
+          _opentype = 'funcbutton'
+        } else {
+          _opentype = form.initVal
+        }
+      } else if (form.key === 'intertype') {
+        _intertype = form.initVal
+      } else if (form.key === 'position') {
+        _position = form.initVal
+      } else if (form.key === 'tabType') {
+        _tabType = form.initVal
+      } else if (form.key === 'funcType') {
+        _funcType = form.initVal
+      }
+    })
+
+    let _tabs = this.props.tabs.filter(tab => tab.type === _tabType)
+
+    if (_opentype === 'innerpage') {                                     // 鏂伴〉闈紙鍐呴儴锛夛紝鍙�夋ā鏉�
+      _options = ['label', 'Ot', 'OpenType', 'pageTemplate', 'icon', 'class', 'position']
+    } else if (_opentype === 'outerpage') {                              // 鏂伴〉闈紙澶栭儴锛夛紝闇�瑕侀〉闈㈠湴鍧�
+      _options = ['label', 'Ot', 'OpenType', 'url', 'icon', 'class', 'position']
+    } else if (_opentype === 'blank' || _opentype === 'tab') {           // 鏂版爣绛炬垨褰撳墠椤甸潰鏇挎崲
+      _options = ['label', 'Ot', 'OpenType', 'icon', 'class', 'position', 'tabTemplate']
+    } else if (_opentype === 'popview') {                                // 妯℃�佹鏍囩椤�
+      _options = ['label', 'Ot', 'OpenType', 'icon', 'class', 'position', 'tabType', 'linkTab', 'popClose']
+    } else if (_opentype === 'excelOut') {    // 瀵煎叆瀵煎嚭
+      if (_intertype === 'outer') {
+        _options = ['label', 'OpenType', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'icon', 'class', 'execSuccess', 'execError', 'pagination', 'search']
+      } else {
+        _options = ['label', 'OpenType', 'intertype', 'innerFunc', 'icon', 'class', 'execSuccess', 'execError', 'pagination', 'search']
+      }
+    } else if (_opentype === 'excelIn') {    // 瀵煎叆瀵煎嚭
+      if (_intertype === 'outer') {
+        _options = ['label', 'Ot', 'OpenType', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc', 'icon', 'class', 'sheet', 'execSuccess', 'execError']
+      } else {
+        _options = ['label', 'Ot', 'OpenType', 'intertype', 'innerFunc', 'icon', 'class', 'sheet', 'execSuccess', 'execError']
+      }
+    } else if (_opentype === 'funcbutton') {
+      if (!_funcType) {
+        _options = ['label', 'OpenType', 'funcType', 'icon', 'class']
+      } else if (_funcType === 'changeuser') {
+        _options = ['label', 'OpenType', 'funcType', 'icon', 'class']
+      } else if (_funcType === 'print') {
+        if (_intertype === 'outer') {
+          _options = ['label', 'OpenType', 'funcType', 'execMode', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError']
+        } else {
+          _options = ['label', 'OpenType', 'funcType', 'execMode', 'intertype', 'innerFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError']
+        }
+      }
+    } else {
+      if (_intertype === 'outer') {
+        _options = ['label', 'position', 'OpenType', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError']
+      } else {
+        _options = ['label', 'position', 'OpenType', 'intertype', 'innerFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError', 'sql', 'sqlType']
+      }
+    }
+    this.setState({
+      openType: _opentype,
+      interType: _intertype,
+      position: _position,
+      funcType: _funcType,
+      formlist: this.props.formlist.map(item => {
+        if (item.key === 'class') {
+          item.options = btnClasses
+        } else if (item.key === 'icon') {
+          item.options = btnIcons
+        } else if (item.key === 'Ot') {
+          if (_opentype === 'innerpage' || _position === 'grid') {
+            item.options = this.state.reqOptionSgl
+          } else if (['outerpage', 'blank', 'tab', 'popview', 'excelIn'].includes(_opentype)) {
+            item.options = this.state.reqOptions
+          } else {
+            item.options = this.state.reqOptionsMutil
+          }
+        } else if (item.key === 'sqlType') {
+          if (['prompt', 'exec'].includes(_opentype)) {
+            item.options = this.state.deleteOptions
+          } else {
+            item.options = this.state.insertUpdateOptions
+          }
+        } else if (item.key === 'linkTab') {
+          item.options = [
+            {
+              value: '',
+              text: '鏂板缓'
+            },
+            ..._tabs
+          ]
+        } else if (item.key === 'OpenType') {
+          item.initVal = _opentype
+        }
+
+        item.hidden = !_options.includes(item.key)
+        return item
+      })
+    })
+  }
+
+  componentDidMount () {
+    const { card } = this.props
+
+    if (card.focus) {
+      try {
+        let _form = document.getElementById('label')
+        _form.select()
+      } catch {
+        console.warn('琛ㄥ崟focus澶辫触锛�')
+      }
+    }
+  }
+
+  /**
+   * @description 涓嬫媺鍒囨崲
+   * 1銆佹墦寮�鏂瑰紡鍒囨崲锛岄噸缃彲瑙佽〃鍗曞拰琛ㄥ崟鍊�
+   * 2銆佹樉绀轰綅缃垏鎹紝閲嶇疆閫夋嫨琛�
+   * 3銆佸垏鎹㈡爣绛剧被鍨嬶紝閲嶇疆鍙�夋爣绛�
+   */
+  openTypeChange = (key, value) => {
+    if (key === 'OpenType') {
+      let _options = null
+      if (value === 'innerpage') {
+        _options = ['label', 'Ot', 'OpenType', 'pageTemplate', 'icon', 'class', 'position']
+      } else if (value === 'outerpage') {
+        _options = ['label', 'Ot', 'OpenType', 'url', 'icon', 'class', 'position']
+      } else if (value === 'blank' || value === 'tab') {
+        _options = ['label', 'Ot', 'OpenType', 'icon', 'class', 'position', 'tabTemplate']
+      } else if (value === 'popview') {
+        _options = ['label', 'Ot', 'OpenType', 'icon', 'class', 'position', 'tabType', 'linkTab', 'popClose']
+      } else if (value === 'excelOut') {
+        if (this.state.interType === 'outer') {
+          _options = ['label', 'OpenType', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'icon', 'class', 'execSuccess', 'execError', 'pagination', 'search']
+        } else {
+          _options = ['label', 'OpenType', 'intertype', 'innerFunc', 'icon', 'class', 'execSuccess', 'execError', 'pagination', 'search']
+        }
+      } else if (value === 'excelIn') {
+        if (this.state.interType === 'outer') {
+          _options = ['label', 'Ot', 'OpenType', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc', 'icon', 'class', 'sheet', 'execSuccess', 'execError']
+        } else {
+          _options = ['label', 'Ot', 'OpenType', 'intertype', 'innerFunc', 'icon', 'class', 'sheet', 'execSuccess', 'execError']
+        }
+      } else if (value === 'funcbutton') {
+        if (!this.state.funcType) {
+          _options = ['label', 'OpenType', 'funcType', 'icon', 'class']
+        } else if (this.state.funcType === 'changeuser') {
+          _options = ['label', 'OpenType', 'funcType', 'icon', 'class']
+        } else if (this.state.funcType === 'print') {
+          if (this.state.interType === 'outer') {
+            _options = ['label', 'OpenType', 'funcType', 'execMode', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError']
+          } else {
+            _options = ['label', 'OpenType', 'funcType', 'execMode', 'intertype', 'innerFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError']
+          }
+        }
+      } else {
+        if (this.state.interType === 'inner') {
+          _options = ['label', 'position', 'OpenType', 'intertype', 'innerFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError', 'sql', 'sqlType']
+        } else {
+          _options = ['label', 'position', 'OpenType', 'intertype', 'innerFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc']
+        }
+      }
+
+      let _fieldval = {}
+      
+      let _formlist = this.state.formlist.map(item => {
+        item.hidden = !_options.includes(item.key)
+
+        if (item.hidden) return item
+
+        if (item.key === 'intertype') {
+          _fieldval.intertype = this.state.interType
+        } else if (item.key === 'Ot') {
+          if (value === 'innerpage' || this.state.position === 'grid') {
+            item.options = this.state.reqOptionSgl
+            _fieldval.Ot = 'requiredSgl'
+          } else if (['outerpage', 'blank', 'tab', 'popview'].includes(value)) {
+            item.options = this.state.reqOptions
+            _fieldval.Ot = 'requiredSgl'
+          } else if (value === 'excelIn') {
+            item.options = this.state.reqOptions
+            _fieldval.Ot = 'notRequired'
+          } else {
+            item.options = this.state.reqOptionsMutil
+          }
+        } else if (item.key === 'sqlType') {
+          if (['prompt', 'exec'].includes(value)) {
+            item.options = this.state.deleteOptions
+          } else {
+            item.options = this.state.insertUpdateOptions
+          }
+          _fieldval.sqlType = ''
+        }
+
+        return item
+      })
+
+      this.setState({
+        openType: value,
+        formlist: _formlist
+      }, () => {
+        this.props.form.setFieldsValue(_fieldval)
+      })
+    } else if (key === 'position') {
+      let _fieldval = {}
+
+      this.setState({
+        position: value,
+        formlist: this.state.formlist.map(item => {
+          if (item.key === 'Ot') {
+            if (this.state.openType === 'innerpage' || value === 'grid') {
+              item.options = this.state.reqOptionSgl
+              _fieldval.Ot = 'requiredSgl'
+            } else if (['outerpage', 'blank', 'tab', 'popview'].includes(this.state.openType)) {
+              item.options = this.state.reqOptions
+              _fieldval.Ot = 'requiredSgl'
+            } else {
+              item.options = this.state.reqOptionsMutil
+            }
+          }
+          return item
+        })
+      }, () => {
+        this.props.form.setFieldsValue(_fieldval)
+      })
+    } else if (key === 'tabType') {
+      let _tabs = this.props.tabs.filter(tab => tab.type === value)
+      let _fieldval = {}
+
+      this.setState({
+        formlist: this.state.formlist.map(item => {
+          if (item.key === 'linkTab') {
+            item.options = [
+              {
+                value: '',
+                text: '鏂板缓'
+              },
+              ..._tabs
+            ]
+          }
+          return item
+        })
+      }, () => {
+        this.props.form.setFieldsValue(_fieldval)
+      })
+    } else if (key === 'funcType') {
+      let _options = null
+      if (!value) {
+        _options = ['label', 'OpenType', 'funcType', 'icon', 'class']
+      } else if (value === 'changeuser') {
+        _options = ['label', 'OpenType', 'funcType', 'icon', 'class']
+      } else if (value === 'print') {
+        if (this.state.interType === 'outer') {
+          _options = ['label', 'OpenType', 'funcType', 'execMode', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError']
+        } else {
+          _options = ['label', 'OpenType', 'funcType', 'execMode', 'intertype', 'innerFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError']
+        }
+      }
+
+      this.setState({
+        formlist: this.state.formlist.map(item => {
+          item.hidden = !_options.includes(item.key)
+
+          if (item.hidden) return item
+
+          if (item.key === 'Ot' && value === 'print') {
+            item.options = this.state.reqOptionsMutil
+          }
+
+          return item
+        })
+      })
+    }
+  }
+
+  onChange = (e, key) => {
+    const { openType } = this.state
+    let value = e.target.value
+    if (key === 'intertype') {
+      let _options = null
+      if (openType === 'excelOut') {
+        if (value === 'outer') {
+          _options = ['label', 'OpenType', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'icon', 'class', 'execSuccess', 'execError', 'pagination', 'search']
+        } else {
+          _options = ['label', 'OpenType', 'intertype', 'innerFunc', 'icon', 'class', 'execSuccess', 'execError', 'pagination', 'search']
+        }
+      } else if (openType === 'excelIn') {
+        if (value === 'outer') {
+          _options = ['label', 'Ot', 'OpenType', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc', 'icon', 'class', 'sheet', 'execSuccess', 'execError']
+        } else {
+          _options = ['label', 'Ot', 'OpenType', 'intertype', 'innerFunc', 'icon', 'class', 'sheet', 'execSuccess', 'execError']
+        }
+      } else if (openType === 'funcbutton') {
+        if (value === 'outer') {
+          _options = ['label', 'OpenType', 'funcType', 'execMode', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError']
+        } else {
+          _options = ['label', 'OpenType', 'funcType', 'execMode', 'intertype', 'innerFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError']
+        }
+      } else {
+        if (value === 'inner') {
+          _options = ['label', 'position', 'OpenType', 'intertype', 'innerFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError', 'sql', 'sqlType']
+        } else {
+          _options = ['label', 'position', 'OpenType', 'intertype', 'innerFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc']
+        }
+      }
+
+      this.setState({
+        interType: value,
+        formlist: this.state.formlist.map(item => {
+          item.hidden = !_options.includes(item.key)
+
+          if (item.key === 'interface') {
+            item.readonly = false
+          } else if (item.key === 'sysInterface') {
+            item.initVal = 'false'
+          }
+          return item
+        })
+      })
+    } else if (key === 'sysInterface') {
+      if (value === 'true') {
+        this.props.form.setFieldsValue({
+          interface: window.GLOB.mainSystemApi || ''
+        })
+      }
+      this.setState({
+        formlist: this.state.formlist.map(item => {
+          if (item.key === 'interface' && value === 'true') {
+            item.readonly = true
+          } else if (item.key === 'interface') {
+            item.readonly = false
+          }
+
+          return item
+        })
+      })
+    }
+  }
+
+  handleSubmit = (e) => {
+    e.preventDefault()
+
+    if (this.props.inputSubmit) {
+      this.props.inputSubmit()
+    }
+  }
+
+  getFields() {
+    const { getFieldDecorator } = this.props.form
+    const fields = []
+
+    this.state.formlist.forEach((item, index) => {
+      if (item.hidden) return
+
+      if (item.type === 'text') { // 鏂囨湰鎼滅储
+        let _rules = []
+        if (item.key === 'innerFunc') {
+          let str = '^(' + item.fields.join('|') + ')'
+          let _patten = new RegExp(str + formRule.func.innerPattern + '$', 'g')
+          _rules = [{
+            pattern: _patten,
+            message: formRule.func.innerMessage
+          }, {
+            max: formRule.func.max,
+            message: formRule.func.maxMessage
+          }]
+        } else if (item.key === 'outerFunc' || item.key === 'callbackFunc') {
+          _rules = [{
+            pattern: formRule.func.pattern,
+            message: formRule.func.message
+          }, {
+            max: formRule.func.max,
+            message: formRule.func.maxMessage
+          }]
+        } else {
+          _rules = [{
+            max: formRule.input.max,
+            message: formRule.input.message
+          }]
+        }
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" overlayClassName={item.tooltipClass} title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || '',
+                rules: [
+                  {
+                    required: item.readonly ? false : !!item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  },
+                  ..._rules
+                ]
+              })(<Input placeholder="" autoComplete="off" disabled={item.readonly} onPressEnter={this.handleSubmit} />)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'number') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" overlayClassName={item.tooltipClass} title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: item.readonly ? false : !!item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  }
+                ]
+              })(<InputNumber min={0} max={10000} precision={0} />)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'select') { // 涓嬫媺鎼滅储
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" overlayClassName={item.tooltipClass} title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || '',
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <Select
+                  showSearch
+                  filterOption={(input, option) => option.props.children[2].toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                  onChange={(value) => {this.openTypeChange(item.key, value)}}
+                  getPopupContainer={() => document.getElementById('winter')}
+                >
+                  {item.options.map((option, index) =>
+                    <Select.Option id={`${index}`} title={option.text} key={`${index}`} value={option.value}>
+                      {item.key === 'icon' && option.value && <Icon type={option.value} />} {option.text}
+                    </Select.Option>
+                  )}
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'radio') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <Radio.Group onChange={(e) => {this.onChange(e, item.key)}} disabled={item.readonly}>
+                  {
+                    item.options.map(option => {
+                      return (
+                        <Radio key={option.value} value={option.value}>{option.text}</Radio>
+                      )
+                    })
+                  }
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'textarea') {
+        fields.push(
+          <Col span={24} key={index}>
+            <Form.Item label={item.label} className="textarea">
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal
+              })(<TextArea rows={4} />)}
+            </Form.Item>
+          </Col>
+        )
+      }
+    })
+    return fields
+  }
+
+  handleConfirm = () => {
+    const { setting } = this.props
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          values.uuid = this.props.card.uuid
+          values.verify = this.props.card.verify || null
+
+          if (values.OpenType === 'excelIn') {
+            values.position = 'toolbar'
+          } else if (values.OpenType === 'excelOut') {
+            if (values.intertype === 'inner' && !values.innerFunc) {
+              if ((setting.interType === 'inner' && setting.innerFunc) || setting.interType === 'outer') {
+                notification.warning({
+                  top: 92,
+                  message: '琛ㄦ牸鏁版嵁鏌ヨ鏈娇鐢ㄦ暟鎹簮锛屽鍑篍xcel浣跨敤鍐呴儴鎺ュ彛鏃讹紝闇�鑷畾涔夊唴閮ㄥ嚱鏁帮紒',
+                  duration: 5
+                })
+                return
+              }
+            }
+            
+            values.position = 'toolbar'
+            values.Ot = 'notRequired'
+          } else if (values.OpenType === 'popview' && !values.linkTab) { // 娌℃湁鍏宠仈鏍囩锛堟柊寤烘椂锛夛紝鍒涘缓鏂版爣绛綢d
+            values.linkTab = Utils.getuuid()
+            values.createTab = true // 鐢ㄤ簬鏍囪鎸夐挳澶嶅埗鏃讹紝鏄惁澶嶅埗鍘熸湁鏍囩
+          } else if (values.OpenType === 'funcbutton') { // 杞崲鎵撳嵃鏃舵墦寮�鏂瑰紡
+            values.position = 'toolbar'
+            if (values.funcType === 'print') {
+              values.OpenType = values.execMode
+            }
+          }
+
+          if (values.innerFunc === '' && values.sql === '') {
+            notification.warning({
+              top: 92,
+              message: this.props.dict['header.form.actionhelp.tablename'],
+              duration: 5
+            })
+          } else if (values.innerFunc === '' && values.sql !== '' && values.sqlType === '') {
+            notification.warning({
+              top: 92,
+              message: this.props.dict['header.form.actionhelp.sqlType'],
+              duration: 5
+            })
+          } else {
+            resolve(values)
+          }
+        } else {
+          reject(err)
+        }
+      })
+    })
+  }
+
+  render() {
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 7 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 17 }
+      }
+    }
+    return (
+      <Form {...formItemLayout} className="ant-advanced-search-form commontable-action-form" id="winter">
+        <Row gutter={24}>{this.getFields()}</Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(MainSearch)
\ No newline at end of file
diff --git a/src/templates/sharecomponent/actioncomponent/actionform/index.scss b/src/templates/sharecomponent/actioncomponent/actionform/index.scss
new file mode 100644
index 0000000..c25cef2
--- /dev/null
+++ b/src/templates/sharecomponent/actioncomponent/actionform/index.scss
@@ -0,0 +1,33 @@
+.ant-advanced-search-form.commontable-action-form {
+  min-height: 190px;
+  .superconfig {
+    color: #1890ff;
+    cursor: pointer;
+  }
+  .textarea {
+    .ant-col-sm-7 {
+      width: 14%;
+    }
+    .ant-col-sm-17 {
+      width: 86%;
+    }
+  }
+  .ant-input-number {
+    width: 100%;
+  }
+  .anticon-question-circle {
+    color: #c49f47;
+    position: relative;
+    left: -3px;
+  }
+  .with-button {
+    .ant-form-item-control-wrapper {
+      padding-right: 63px;
+    }
+    .ant-btn {
+      position: absolute;
+      right: 12px;
+      top: 4.5px;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/templates/sharecomponent/actioncomponent/dragaction/card.jsx b/src/templates/sharecomponent/actioncomponent/dragaction/card.jsx
new file mode 100644
index 0000000..946a950
--- /dev/null
+++ b/src/templates/sharecomponent/actioncomponent/dragaction/card.jsx
@@ -0,0 +1,60 @@
+import React from 'react'
+import { useDrag, useDrop } from 'react-dnd'
+import { Icon, Button } from 'antd'
+import './index.scss'
+
+const Card = ({ id, card, moveCard, findCard, editCard, delCard, copyCard, profileCard, hasDrop, doubleClickCard }) => {
+  const originalIndex = findCard(id).index
+  const [{ isDragging }, drag] = useDrag({
+    item: { type: 'action', id, originalIndex },
+    collect: monitor => ({
+      isDragging: monitor.isDragging(),
+    }),
+  })
+  const [, drop] = useDrop({
+    accept: 'action',
+    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
+
+  let hasProfile = false
+  if (['pop', 'prompt', 'exec'].includes(card.OpenType)) {
+    hasProfile = true
+  } else if (card.OpenType === 'excelIn' || card.OpenType === 'excelOut') {
+    hasProfile = true
+  } else if (card.funcType === 'print') {
+    hasProfile = true
+  }
+
+  return (
+    <div className="page-card" style={{ opacity: opacity}}>
+      <div ref={node => drag(drop(node))}>
+        <Button
+          className={'mk-btn mk-' + card.class}
+          icon={card.icon}
+          key={card.uuid}
+          onDoubleClick={() => doubleClickCard(id)}
+        >
+          {card.label}{card.position === 'grid' && <Icon type="table" />}
+        </Button>
+      </div>
+      <Icon className="edit" title="edit" type="edit" onClick={() => editCard(id)} />
+      <Icon className="edit copy" title="copy" type="copy" onClick={() => copyCard(id)} />
+      <Icon className="edit close" title="close" type="close" onClick={() => delCard(id)} />
+      {hasProfile ? <Icon className="edit profile" title="verify" type="profile" onClick={() => profileCard(id)} /> : null}
+    </div>
+  )
+}
+export default Card
diff --git a/src/templates/sharecomponent/actioncomponent/dragaction/index.jsx b/src/templates/sharecomponent/actioncomponent/dragaction/index.jsx
new file mode 100644
index 0000000..d6e05a2
--- /dev/null
+++ b/src/templates/sharecomponent/actioncomponent/dragaction/index.jsx
@@ -0,0 +1,179 @@
+import React, { useState } from 'react'
+import { useDrop } from 'react-dnd'
+import { is, fromJS } from 'immutable'
+import update from 'immutability-helper'
+import Utils from '@/utils/utils.js'
+import Card from './card'
+import './index.scss'
+
+const Container = ({list, setting, placeholder, handleList, handleMenu, deleteMenu, profileMenu, doubleClickCard }) => {
+  let target = null
+
+  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(_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 doubleClickBtn = id => {
+    const { card } = findCard(id)
+    doubleClickCard(card)
+  }
+
+  const editCard = id => {
+    const { card } = findCard(id)
+    handleMenu(card)
+  }
+  
+  const profileCard = id => {
+    const { card } = findCard(id)
+    profileMenu(card)
+  }
+
+  const delCard = id => {
+    const { card } = findCard(id)
+    deleteMenu(card)
+  }
+
+  const copyCard = id => {
+    const { card } = findCard(id)
+    let copycard = fromJS(card).toJS()
+
+    copycard.uuid = Utils.getuuid()
+    copycard.origin = false
+    copycard.copyType = 'action'
+    copycard.label = copycard.label + '(copy)'
+    copycard.focus = true
+
+    copycard.originCard = card
+
+    if (copycard.OpenType === 'popview') { // 寰呭畬鍠�
+      copycard.linkTab = ''
+    }
+
+    let _val = fromJS(copycard).toJS()
+
+    try {
+      _val.uuid = Utils.getuuid()
+      _val = window.btoa(window.encodeURIComponent(JSON.stringify(_val)))
+    } catch {
+      console.warn('Stringify Failure')
+      _val = ''
+    }
+
+    if (_val) {
+      let oInput = document.createElement('input')
+      oInput.value = _val
+      document.body.appendChild(oInput)
+      oInput.select()
+      document.execCommand('Copy')
+      document.body.removeChild(oInput)
+    }
+
+    const { index: overIndex } = findCard(id)
+
+    const _cards = update(cards, { $splice: [[overIndex + 1, 0, copycard]] })
+
+    handleList(_cards, copycard)
+  }
+
+  const hasDrop = (item) => {
+    target = item
+  }
+
+  const [, drop] = useDrop({
+    accept: 'action',
+    drop(item) {
+      if (item.hasOwnProperty('originalIndex')) {
+        return
+      }
+
+      let newcard = {}
+      newcard.uuid = Utils.getuuid()
+      newcard.focus = true
+      
+      newcard.label = 'button'
+      newcard.sqlType = ''
+      newcard.Ot = 'requiredSgl'
+      newcard.OpenType = item.subType
+      newcard.tabType = 'SubTable'
+      newcard.icon = ''
+      newcard.class = 'default'
+      newcard.intertype = 'inner'
+      newcard.method = 'POST'
+      newcard.position = 'toolbar'
+      newcard.execSuccess = 'grid'
+      newcard.execError = 'never'
+      newcard.popClose = 'never'
+      newcard.errorTime = 10
+      newcard.verify = null
+
+      if (item.subType === 'excelIn') {
+        // 瀵煎叆鍜屽鍑篹xcel锛屾寜閽悕绉扮洿鎺ヤ负瀵煎叆銆佸鍑�
+        newcard.label = item.label
+      } else if (item.subType === 'excelOut') {
+        newcard.label = item.label
+        newcard.intertype = setting.interType
+        newcard.innerFunc = setting.innerFunc
+        newcard.sysInterface = setting.sysInterface
+        newcard.outerFunc = setting.outerFunc
+        newcard.interface = setting.interface
+      }
+      
+      let targetId = cards.length > 0 ? cards[cards.length - 1].uuid : 0
+      if (target) {
+        targetId = target.uuid
+      }
+
+      const { index: overIndex } = findCard(`${targetId}`)
+      let targetIndex = overIndex
+
+      targetIndex++
+
+      const _cards = update(cards, { $splice: [[targetIndex, 0, newcard]] })
+
+      handleList(_cards, newcard)
+      target = null
+    }
+  })
+
+  return (
+    <div ref={drop} className="ant-row">
+      {cards.map(card => (
+        <Card
+          id={card.uuid}
+          key={card.uuid}
+          card={card}
+          moveCard={moveCard}
+          copyCard={copyCard}
+          editCard={editCard}
+          delCard={delCard}
+          findCard={findCard}
+          hasDrop={hasDrop}
+          profileCard={profileCard}
+          doubleClickCard={doubleClickBtn}
+        />
+      ))}
+      
+      {cards.length === 0 ?
+        <div className="common-drawarea-placeholder">
+          {placeholder}
+        </div> : null
+      }
+    </div>
+  )
+}
+export default Container
diff --git a/src/templates/sharecomponent/actioncomponent/dragaction/index.scss b/src/templates/sharecomponent/actioncomponent/dragaction/index.scss
new file mode 100644
index 0000000..369ae98
--- /dev/null
+++ b/src/templates/sharecomponent/actioncomponent/dragaction/index.scss
@@ -0,0 +1,6 @@
+.common-drawarea-placeholder {
+  width: 100%;
+  line-height: 65px;
+  text-align: center;
+  color: #bcbcbc;
+}
\ No newline at end of file
diff --git a/src/templates/sharecomponent/actioncomponent/index.jsx b/src/templates/sharecomponent/actioncomponent/index.jsx
new file mode 100644
index 0000000..e7babb6
--- /dev/null
+++ b/src/templates/sharecomponent/actioncomponent/index.jsx
@@ -0,0 +1,921 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { fromJS } from 'immutable'
+import { Icon, Tooltip, Modal, notification, Button } from 'antd'
+import moment from 'moment'
+
+import Api from '@/api'
+import Utils from '@/utils/utils.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import { getActionForm } from '@/templates/zshare/formconfig'
+
+import ActionForm from './actionform'
+import VerifyCard from '@/templates/zshare/verifycard'
+import CreateFunc from '@/templates/zshare/createfunc'
+import CreateInterface from '@/templates/zshare/createinterface'
+import VerifyPrint from './verifyprint'
+import VerifyExcelIn from './verifyexcelin'
+import VerifyExcelOut from './verifyexcelout'
+import DragElement from './dragaction'
+import './index.scss'
+
+const { confirm } = Modal
+
+// **鎮茶鑰呭線寰�姝g‘锛屼箰瑙傝�呭線寰�鎴愬姛
+class ActionComponent extends Component {
+  static propTpyes = {
+    type: PropTypes.string,          // 鑿滃崟绫诲瀷锛屼富琛ㄦ垨瀛愯〃
+    menu: PropTypes.object,          // 鑿滃崟淇℃伅锛堣彍鍗昳d锛岃彍鍗曞弬鏁帮紝鑿滃崟鍚嶇О锛�
+    config: PropTypes.object,        // 鑿滃崟閰嶇疆淇℃伅
+    pasteContent: PropTypes.object,  // 绮樿创閰嶇疆淇℃伅
+    usefulFields: PropTypes.array,   // 鑷畾涔夊嚱鏁板彲鐢ㄥ瓧娈�
+    tabs: PropTypes.array,           // 鎵�鏈夋爣绛�
+    setSubConfig: PropTypes.func,    // 璁剧疆瀛愰厤缃俊鎭�
+    updateaction: PropTypes.func     // 鑿滃崟閰嶇疆鏇存柊
+  }
+
+  state = {
+    dict: (!localStorage.getItem('lang') || localStorage.getItem('lang') === 'zh-CN') ? zhCN : enUS,
+    card: null,          // 缂栬緫涓厓绱�
+    formlist: null,      // 琛ㄥ崟淇℃伅
+    actionlist: null,    // 鎸夐挳缁�
+    copying: false,      // 鎸夐挳澶嶅埗涓�
+    visible: false,      // 妯℃�佹鎺у埗
+    profVisible: false   // 楠岃瘉淇℃伅妯℃�佹
+  }
+
+  /**
+   * @description 鎼滅储鏉′欢鍒濆鍖�
+   */
+  UNSAFE_componentWillMount () {
+    this.setState({
+      actionlist: fromJS(this.props.config.action).toJS()
+    })
+  }
+
+  /**
+   * @description 鐩戝惉鍒版寜閽鍒舵椂锛岃Е鍙戞寜閽紪杈�
+   */
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    const { actionlist } = this.state
+
+    if (nextProps.pasteContent && nextProps.pasteContent.copyType === 'action') {
+      this.setState({actionlist: [...actionlist, nextProps.pasteContent]})
+      this.handleAction(nextProps.pasteContent)
+    }
+  }
+
+  /**
+   * @description 鎸夐挳椤哄簭璋冩暣锛屾垨鎷栨嫿娣诲姞
+   */
+  handleList = (list, card) => {
+    const { config } = this.props
+
+    if (card) {
+      this.setState({actionlist: list})
+      this.handleAction(card)
+    } else {
+      this.setState({actionlist: list})
+      this.props.updateaction({...config, action: list})
+    }
+  }
+
+  /**
+   * @description 鎼滅储鏉′欢缂栬緫锛岃幏鍙栨悳绱㈡潯浠惰〃鍗曚俊鎭�
+   */
+  handleAction = (card) => {
+    let ableField = this.props.usefulFields.join(', ')
+    let functip = <div>
+      <p style={{marginBottom: '5px'}}>{this.state.dict['model.tooltip.func.innerface'].replace('@ableField', ableField)}</p>
+      <p>{this.state.dict['model.tooltip.func.outface']}</p>
+    </div>
+
+    this.setState({
+      visible: true,
+      card: card,
+      formlist: getActionForm(card, functip, this.props.config, this.props.usefulFields, this.props.type)
+    })
+  }
+
+  /**
+   * @description 鍙栨秷淇濆瓨锛屽鏋滃厓绱犱负鏂版坊鍏冪礌锛屽垯浠庡簭鍒椾腑鍒犻櫎
+   */
+  editModalCancel = () => {
+    const { card } = this.state
+
+    if (card.focus) {
+      let actionlist = fromJS(this.state.actionlist).toJS()
+
+      actionlist = actionlist.filter(item => item.uuid !== card.uuid)
+
+      this.setState({
+        card: null,
+        actionlist: actionlist,
+        visible: false
+      })
+    } else {
+      this.setState({
+        card: null,
+        visible: false
+      })
+    }
+  }
+
+  /**
+   * @description 鎼滅储淇敼鍚庢彁浜や繚瀛�
+   * 1銆佸幓闄ょ郴缁熼粯璁ゆ悳绱㈡潯浠�
+   * 2銆佸瓧娈靛強鎻愮ず鏂囧瓧閲嶅鏍¢獙
+   * 3銆佹洿鏂颁笅鎷夎彍鍗曞彲閫夐泦鍚�
+   * 4銆佷笅鎷夎彍鍗曟暟鎹簮璇硶楠岃瘉
+   */
+  handleSubmit = () => {
+    const { config, menu } = this.props
+    const { card } = this.state
+    let _actionlist = fromJS(this.state.actionlist).toJS()
+
+    this.actionFormRef.handleConfirm().then(btn => {
+      _actionlist = _actionlist.filter(item => !item.origin || item.uuid === btn.uuid)
+
+      let labelrepet = false
+      _actionlist = _actionlist.map(item => {
+        if (item.uuid !== btn.uuid && item.label === btn.label) {
+          labelrepet = true
+        }
+
+        if (item.uuid === btn.uuid) {
+          return btn
+        } else {
+          return item
+        }
+      })
+
+      if (labelrepet) {
+        notification.warning({
+          top: 92,
+          message: this.state.dict['model.name.exist'] + ' !',
+          duration: 5
+        })
+        return
+      }
+
+      this.setState({
+        copying: true
+      })
+
+      let copyActionId = '' // 鎸夐挳涓哄鍒舵椂锛岃褰曞綋鍓嶆寜閽殑Id锛岃彍鍗曞彇娑堜繚瀛樻椂锛屽垹闄ゅ鍒舵寜閽厤缃俊鎭�
+
+      /**
+       * @description 鎸夐挳淇濆瓨鏍¢獙
+       * 1銆佹鏌ユ寜閽槸鍚︿负琛ㄥ崟鎴栬〃鍗曟爣绛鹃〉锛屽鍓嶅悗涓�鑷达紝鍒欏鍒跺叾鍐呭
+       * 2銆佹鏌ユ寜閽槸鍚︿负鏍囩椤碉紝濡傚墠鍚庝竴鑷达紝鍒欏鍒舵爣绛鹃〉
+       */
+      new Promise(resolve => {
+        if (
+          !card.originCard ||
+          (btn.OpenType === 'pop' && card.originCard.OpenType !== 'pop') ||
+          (['tab', 'blank'].includes(btn.OpenType) && !['tab', 'blank'].includes(card.originCard.OpenType)) ||
+          (btn.OpenType === 'popview' && (!btn.createTab || card.originCard.OpenType !== 'popview' || !card.originCard.linkTab))
+        ) { // 鎸夐挳涓嶆槸澶嶅埗锛屾垨鎸夐挳鍓嶅悗绫诲瀷涓嶄竴鑷存椂锛岀洿鎺ヤ繚瀛�
+          resolve('save')
+        } else if (btn.OpenType === 'pop' || btn.OpenType === 'tab' || btn.OpenType === 'blank') {
+          resolve('subconf')
+        } else if (btn.OpenType === 'popview') {
+          resolve('subtab')
+        } else {
+          resolve('save')
+        }
+      }).then(result => { // 鏌ヨ鍘熸寜閽厤缃俊鎭�
+        if (result === 'save' || result === 'subtab') return result
+
+        return Api.getSystemConfig({
+          func: 'sPC_Get_LongParam',
+          MenuID: card.originCard.uuid
+        })
+      }).then(result => { // 澶嶅埗鎸夐挳閰嶇疆淇℃伅锛屼繚瀛樿嚦鏂版坊鍔犳寜閽�
+        if (result === 'save' || result === 'subtab') return result
+
+        if (result.status && result.LongParam) {
+          let _LongParam = ''
+
+          // 瑙f瀽閰嶇疆
+          if (result.LongParam) {
+            try {
+              _LongParam = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam)))
+            } catch (e) {
+              console.warn('Parse Failure')
+              _LongParam = ''
+            }
+          }
+
+          let _temp = '' // 閰嶇疆淇℃伅绫诲瀷
+
+          // 淇敼妯℃�佹鏍囬鍚嶇О
+          if (btn.OpenType === 'pop' && _LongParam && _LongParam.type === 'Modal') {
+            try {
+              _LongParam.setting.title = btn.label
+              _LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(_LongParam)))
+              _temp = 'Modal'
+            } catch {
+              console.warn('Stringify Failure')
+              _LongParam = ''
+              _temp = ''
+            }
+          } else if (['tab', 'blank'].includes(btn.OpenType) && _LongParam && _LongParam.type === 'FormTab') {
+            try {
+              _LongParam.action = _LongParam.action.map(_btn => {
+                _btn.uuid = Utils.getuuid()
+
+                return _btn
+              })
+              _LongParam.tabgroups.forEach(_groupId => {
+                _LongParam[_groupId] = _LongParam[_groupId].map(_tab => {
+                  _tab.uuid = Utils.getuuid()
+
+                  return _tab
+                })
+              })
+              _LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(_LongParam)))
+              _temp = 'FormTab'
+            } catch {
+              console.warn('Stringify Failure')
+              _LongParam = ''
+              _temp = ''
+            }
+          }
+
+          if (!_temp) return 'save'
+
+          let param = {
+            func: 'sPC_ButtonParam_AddUpt',
+            ParentID: menu.MenuID,
+            MenuID: btn.uuid,
+            MenuNo: menu.MenuNo,
+            Template: _temp,
+            MenuName: btn.label,
+            PageParam: JSON.stringify({Template: _temp}),
+            LongParam: _LongParam
+          }
+
+          return Api.getSystemConfig(param)
+        } else {
+          if (!result.status) {
+            notification.warning({
+              top: 92,
+              message: result.message,
+              duration: 5
+            })
+          }
+          return 'save'
+        }
+      }).then(result => {
+        if (result === 'save' || result === 'subtab') return result
+
+        if (!result.status) {
+          notification.warning({
+            top: 92,
+            message: result.message,
+            duration: 5
+          })
+        } else {
+          copyActionId = btn.uuid
+        }
+
+        return 'save'
+      }).then(result => { // 鏌ヨ鍘熸寜閽叧鑱旀爣绛句俊鎭�
+        if (result === 'save') return result
+
+        return Api.getSystemConfig({
+          func: 'sPC_Get_LongParam',
+          MenuID: card.originCard.linkTab
+        })
+      }).then(result => { // 鏍囩澶嶅埗
+        if (result === 'save') return result
+
+        let _LongParam = '' // 鏍囩閰嶇疆淇℃伅
+
+        if (!result.status) {
+          notification.warning({
+            top: 92,
+            message: result.message,
+            duration: 5
+          })
+        } else if (result.LongParam) {
+          // 瑙f瀽鏍囩閰嶇疆
+          try {
+            _LongParam = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam)))
+          } catch (e) {
+            console.warn('Parse Failure')
+            _LongParam = ''
+          }
+        }
+
+        if (!_LongParam) {
+          return 'save'
+        } else {
+          copyActionId = btn.linkTab
+
+          return new Promise(resolve => {
+            this.copytab(btn, _LongParam, resolve)
+          })
+        }
+      }).then(() => {
+        // 鍒ゆ柇鏄惁瀛樺湪鎿嶄綔鍒�
+        let _hasGridbtn = _actionlist.filter(act => act.position === 'grid').length > 0
+        let _gridBtn = config.gridBtn ? fromJS(config.gridBtn).toJS() : null
+
+        if (_gridBtn) {
+          _gridBtn.display = _hasGridbtn
+        } else {
+          _gridBtn = {
+            display: _hasGridbtn,
+            Align: 'center',
+            IsSort: 'false',
+            uuid: Utils.getuuid(),
+            label: this.state.dict['header.form.column.action'],
+            type: 'action',
+            style: 'button',
+            show: 'horizontal',
+            Width: 120
+          }
+        }
+
+        this.setState({
+          actionlist: _actionlist,
+          copying: false,
+          visible: false
+        })
+
+        this.props.updateaction({...config, action: _actionlist, gridBtn: _gridBtn}, copyActionId)
+      })
+    })
+  }
+
+  /**
+   * @description 鏍囩澶嶅埗
+   * 1銆佷繚瀛樻寜閽叧鑱旂殑鏂版爣绛�
+   * 2銆佷繚瀛樻爣绛炬寜閽俊鎭�
+   * 3銆佷繚瀛樻柊鏍囩涓寜閽殑瀛愰厤缃俊鎭�
+   */
+  copytab = (btn, _tab, _resolve) => {
+    let _LongParam = ''
+
+    _tab.uuid = btn.linkTab
+    _tab.tabName = _tab.tabName + moment().format('YYYY-MM-DD HH:mm:ss')
+    _tab.tabNo = _tab.tabNo + moment().format('YYYY-MM-DD HH:mm:ss')
+
+    let param = {
+      func: 'sPC_Tab_AddUpt',
+      MenuID: _tab.uuid,
+      MenuNo: _tab.tabNo,
+      Template: _tab.Template,
+      MenuName: _tab.tabName,
+      Remark: _tab.Remark,
+      PageParam: JSON.stringify({Template: _tab.Template}),
+      Sort: 0
+    }
+
+    let _oriActions = []
+
+    let btnParam = {
+      func: 'sPC_Button_AddUpt',
+      Type: 40,
+      ParentID: _tab.uuid,
+      MenuNo: _tab.tabNo,
+      Template: _tab.Template,
+      PageParam: '',
+      LongParam: '',
+      LText: ''
+    }
+
+    try {
+      let _linkchange = {}
+      btnParam.LText = []
+
+      _tab.action = _tab.action.map((item, index) => {
+        let uuid = Utils.getuuid()
+
+        if (item.OpenType === 'pop') {
+          _oriActions.push({
+            prebtn: JSON.parse(JSON.stringify(item)),
+            curuuid: uuid,
+            Template: 'Modal'
+          })
+        } else if (item.OpenType === 'popview') {
+          _linkchange[item.linkTab] = Utils.getuuid()
+
+          item.linkTab = _linkchange[item.linkTab]
+        }
+
+        item.uuid = uuid
+
+        btnParam.LText.push(`select '${item.uuid}' as menuid, '${item.label}' as menuname, '${(index + 1) * 10}' as Sort`)
+
+        return item
+      })
+
+      if (_tab.funcs && _tab.funcs.length > 0) {
+        _tab.funcs = _tab.funcs.map(item => {
+          if (item.type === 'tab') {
+            item.linkTab = _linkchange[item.linkTab]
+            item.menuNo = ''
+            item.subfuncs = []
+          }
+
+          return item
+        })
+      }
+
+      btnParam.LText = btnParam.LText.join(' union all ')
+      btnParam.LText = Utils.formatOptions(btnParam.LText)
+      btnParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
+      btnParam.secretkey = Utils.encrypt(btnParam.LText, btnParam.timestamp)
+
+      _LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(_tab)))
+    } catch {
+      console.warn('Stringify Failure')
+      _LongParam = ''
+      _resolve('save')
+      return
+    }
+
+    param.LongParam = _LongParam
+
+    new Promise(resolve => {
+      Api.getSystemConfig(param).then(response => {
+        if (response.status) {
+          resolve(true)
+        } else {
+          notification.warning({
+            top: 92,
+            message: response.message,
+            duration: 5
+          })
+          resolve(false)
+        }
+      })
+    }).then(result => {
+      if (!result) return result
+      if (!btnParam.LText) return true
+
+      return Api.getSystemConfig(btnParam)
+    }).then(result => {
+      if (result === false || result === true) return result
+
+      if (result.status) {
+        return true
+      } else {
+        notification.warning({
+          top: 92,
+          message: result.message,
+          duration: 5
+        })
+        return false
+      }
+    }).then(result => {
+      if (!result) return result
+      if (_oriActions.length === 0) return true
+
+      let deffers = _oriActions.map(item => {
+        return new Promise(resolve => {
+          Api.getSystemConfig({
+            func: 'sPC_Get_LongParam',
+            MenuID: item.prebtn.uuid
+          }).then(response => {
+            if (!response.status || !response.LongParam) {
+              resolve(response)
+            } else {
+              let _param = {
+                func: 'sPC_ButtonParam_AddUpt',
+                ParentID: _tab.uuid,
+                MenuID: item.curuuid,
+                MenuNo: _tab.tabNo,
+                Template: item.Template,
+                MenuName: item.prebtn.label,
+                PageParam: JSON.stringify({Template: item.Template}),
+                LongParam: response.LongParam
+              }
+              Api.getSystemConfig(_param).then(resp => {
+                resolve(resp)
+              })
+            }
+          })
+        })
+      })
+
+      return Promise.all(deffers)
+    }).then(result => {
+      let error = ''
+
+      if (typeof(result) === 'object') {
+        result.forEach(resul => {
+          if (!resul.status && !error) {
+            error = resul
+          }
+        })
+      }
+      
+      if (error) {
+        notification.warning({
+          top: 92,
+          message: error.message,
+          duration: 5
+        })
+      }
+
+      _resolve('save')
+    })
+  }
+
+  /**
+   * @description 鎸夐挳鍒犻櫎
+   */
+  deleteElement = (card) => {
+    const { config } = this.props
+    const { dict } = this.state
+    let _this = this
+
+    confirm({
+      content: dict['model.confirm'] + dict['model.delete'] + ` - ${card.label} 锛焋,
+      okText: dict['model.confirm'],
+      cancelText: this.state.dict['header.cancel'],
+      onOk() {
+        let _actionlist = fromJS(_this.state.actionlist).toJS()
+
+        _actionlist = _actionlist.filter(item => item.uuid !== card.uuid)
+
+        _this.setState({
+          actionlist: _actionlist
+        })
+        
+        let _hasGridbtn = _actionlist.filter(act => act.position === 'grid').length > 0
+        let _gridBtn = config.gridBtn ? fromJS(config.gridBtn).toJS() : null
+
+        if (_gridBtn) {
+          _gridBtn.display = _hasGridbtn
+        } else {
+          _gridBtn = {
+            display: _hasGridbtn,
+            Align: 'center',
+            IsSort: 'false',
+            uuid: Utils.getuuid(),
+            label: this.state.dict['header.form.column.action'],
+            type: 'action',
+            style: 'button',
+            show: 'horizontal',
+            Width: 120
+          }
+        }
+
+        let delcard = {
+          type: 'action',
+          card: card
+        }
+
+        _this.props.updateaction({...config, action: _actionlist, gridBtn: _gridBtn}, '', delcard)
+      },
+      onCancel() {}
+    })
+  }
+
+  /**
+   * @description 楠岃瘉淇℃伅閰嶇疆
+   */
+  profileAction = (element) => {
+    this.setState({
+      profVisible: true,
+      card: element
+    })
+  }
+
+  /**
+   * @description 楠岃瘉淇℃伅淇濆瓨
+   */
+  verifySubmit = () => {
+    const { config } = this.props
+    const { card } = this.state
+    
+    this.verifyRef.handleConfirm().then(res => {
+      let _actionlist = fromJS(this.state.actionlist).toJS()
+
+      _actionlist = _actionlist.filter(item => !item.origin || item.uuid === card.uuid)
+
+      _actionlist = _actionlist.map(item => {
+        if (item.uuid === card.uuid) {
+          item.verify = res
+        }
+  
+        return item
+      })
+
+      this.setState({
+        actionlist: _actionlist,
+        profVisible: false
+      })
+      this.props.updateaction({...config, action: _actionlist})
+    })
+  }
+
+  /**
+   * @description 鍒涘缓鎸夐挳瀛樺偍杩囩▼
+   */
+  creatFunc = () => {
+    const { menu, config } = this.props
+    let _config = fromJS(this.props.config).toJS()
+
+    this.actionFormRef.handleConfirm().then(res => {
+      let btn = res         // 鎸夐挳淇℃伅
+      let newLText = ''     // 鍒涘缓瀛樺偍杩囩▼sql
+      let DelText = ''      // 鍒犻櫎瀛樺偍杩囩▼sql
+
+      let _actionlist = fromJS(this.state.actionlist).toJS()
+
+      _actionlist = _actionlist.filter(item => !item.origin || item.uuid === btn.uuid)
+
+      let labelrepet = false
+      _actionlist = _actionlist.map(item => {
+        if (item.uuid !== btn.uuid && item.label === btn.label) {
+          labelrepet = true
+        }
+
+        if (item.uuid === btn.uuid) {
+          return btn
+        } else {
+          return item
+        }
+      })
+
+      if (labelrepet) {
+        notification.warning({
+          top: 92,
+          message: this.state.dict['model.name.exist'] + ' !',
+          duration: 5
+        })
+        return
+      }
+
+      // 鍒涘缓瀛樺偍杩囩▼锛屽繀椤诲~鍐欏唴閮ㄥ嚱鏁板悕
+      if (!btn.innerFunc) {
+        notification.warning({
+          top: 92,
+          message: '璇峰~鍐欏唴閮ㄥ嚱鏁帮紒',
+          duration: 5
+        })
+        return
+      }
+
+      new Promise(resolve => {
+        // 寮圭獥锛堣〃鍗曪級绫绘寜閽紝鍏堣幏鍙栨寜閽厤缃俊鎭紝濡傛灉灏氭湭閰嶇疆鎸夐挳鍒欎細鎶ラ敊骞剁粓姝€��
+        // 鑾峰彇淇℃伅鍚庣敓鎴愬垹闄ゅ拰鍒涘缓瀛樺偍杩囩▼鐨勮鍙�
+        if (btn.OpenType === 'pop') {
+          Api.getSystemConfig({
+            func: 'sPC_Get_LongParam',
+            MenuID: btn.uuid
+          }).then(res => {
+            let _LongParam = ''
+            if (res.status && res.LongParam) {
+              try {
+                _LongParam = JSON.parse(window.decodeURIComponent(window.atob(res.LongParam)))
+              } catch (e) {
+                console.warn('Parse Failure')
+                _LongParam = ''
+              }
+            }
+
+            if (_LongParam) {
+              let fields = []
+              if (_LongParam.groups.length > 0) {
+                _LongParam.groups.forEach(group => {
+                  fields = [...fields, ...group.sublist]
+                })
+              } else {
+                fields = _LongParam.fields
+              }
+
+              let _param = {
+                funcName: btn.innerFunc,
+                name: _config.setting.tableName || '',
+                fields: fields,
+                menuNo: menu.MenuNo
+              }
+              newLText = Utils.formatOptions(Utils.getfunc(_param, btn, menu, _config))
+              DelText = Utils.formatOptions(Utils.dropfunc(btn.innerFunc))
+              resolve(true)
+            } else {
+              notification.warning({
+                top: 92,
+                message: '寮圭獥锛堣〃鍗曪級鎸夐挳锛岃鍏堥厤缃〃鍗曚俊鎭紒',
+                duration: 5
+              })
+              resolve(false)
+            }
+          })
+        } else if (btn.OpenType === 'excelIn') {
+          if (btn.verify && btn.verify.sheet && btn.verify.columns && btn.verify.columns.length > 0) {
+            let _param = {
+              funcName: btn.innerFunc,
+              menuNo: menu.MenuNo
+            }
+            newLText = Utils.formatOptions(Utils.getexcelInfunc(_param, btn, menu))
+            DelText = Utils.formatOptions(Utils.dropfunc(btn.innerFunc))
+            resolve(true)
+          } else {
+            notification.warning({
+              top: 92,
+              message: '璇峰畬鍠勫鍏xcel楠岃瘉淇℃伅锛�',
+              duration: 5
+            })
+            resolve(false)
+          }
+        } else if (btn.OpenType === 'excelOut') {
+          let _param = {
+            innerFunc: btn.innerFunc
+          }
+
+          newLText = Utils.formatOptions(Utils.getTableFunc(_param, menu, _config)) // 鍒涘缓瀛樺偍杩囩▼sql
+          DelText = Utils.formatOptions(Utils.dropfunc(btn.innerFunc))
+
+          resolve(true)
+        } else {
+          let _param = {
+            funcName: btn.innerFunc,
+            name: _config.setting.tableName || '',
+            fields: '',
+            menuNo: menu.MenuNo
+          }
+          newLText = Utils.formatOptions(Utils.getfunc(_param, btn, menu, _config))
+          DelText = Utils.formatOptions(Utils.dropfunc(btn.innerFunc))
+          resolve(true)
+        }
+      }).then(res => {
+        if (!res) return
+
+        this.refs.btnCreatFunc.exec(btn.innerFunc, newLText, DelText).then(result => {
+          if (result !== 'success') return
+
+          // 鍒ゆ柇鏄惁瀛樺湪鎿嶄綔鍒�
+          let _hasGridbtn = _actionlist.filter(act => act.position === 'grid').length > 0
+          let _gridBtn = config.gridBtn ? fromJS(config.gridBtn).toJS() : null
+
+          if (_gridBtn) {
+            _gridBtn.display = _hasGridbtn
+          } else {
+            _gridBtn = {
+              display: _hasGridbtn,
+              Align: 'center',
+              IsSort: 'false',
+              uuid: Utils.getuuid(),
+              label: this.state.dict['header.form.column.action'],
+              type: 'action',
+              style: 'button',
+              show: 'horizontal',
+              Width: 120
+            }
+          }
+
+          this.setState({
+            actionlist: _actionlist
+          })
+
+          this.props.updateaction({...config, action: _actionlist, gridBtn: _gridBtn})
+        })
+      })
+    })
+  }
+
+  /**
+   * @description 鍒涘缓鎸夐挳鎺ュ彛锛堝啓鍏ワ級
+   */
+  btnCreatInterface = () => {
+    const { config, menu, type } = this.props
+
+    this.actionFormRef.handleConfirm().then(result => {
+      
+      let _menu = {
+        type: type,
+        MenuID: menu.MenuID,
+        menuName: menu.MenuName,
+        menuNo: menu.MenuNo
+      }
+      
+      this.refs.btnCreatInterface.triggerInInterface(result, config, _menu)
+    })
+  }
+
+  /**
+   * @description 鎸夐挳鍙屽嚮瑙﹀彂瀛愰厤缃�
+   */
+  btnDoubleClick = (element) => {
+    if (!element.origin && (element.OpenType === 'pop' || element.OpenType === 'popview' || element.OpenType === 'blank' || element.OpenType === 'tab')) {
+      this.props.setSubConfig(element)
+    } else {
+      notification.warning({
+        top: 92,
+        message: '姝ゆ寜閽棤瀛愰厤缃」锛�',
+        duration: 5
+      })
+    }
+  }
+
+  render() {
+    const { config } = this.props
+    const { actionlist, visible, card, dict, copying, profVisible } = this.state
+
+    let hasbtncrtinter = false
+    if (card && !card.copyType && config.setting.interType === 'inner' && !config.setting.innerFunc && config.setting.dataresource) {
+      hasbtncrtinter = true
+    }
+
+    return (
+      <div className="model-table-action-list">
+        <Tooltip placement="bottomLeft" overlayClassName="middle" title={dict['model.tooltip.action.guide']}>
+          <Icon type="question-circle" />
+        </Tooltip>
+        <DragElement
+          list={actionlist}
+          setting={this.props.config.setting}
+          handleList={this.handleList}
+          handleMenu={this.handleAction}
+          deleteMenu={this.deleteElement}
+          profileMenu={this.profileAction}
+          doubleClickCard={this.btnDoubleClick}
+          placeholder={dict['header.form.action.placeholder']}
+        />
+        {/* 缂栬緫鎸夐挳锛氬鍒躲�佺紪杈� */}
+        <Modal
+          title={dict['model.action'] + '-' + (card && card.copyType === 'action' ? dict['model.copy'] : dict['model.edit'])}
+          visible={visible}
+          width={750}
+          maskClosable={false}
+          onCancel={this.editModalCancel}
+          footer={[
+            hasbtncrtinter ? <CreateInterface key="interface" dict={dict} ref="btnCreatInterface" trigger={this.btnCreatInterface}/> : null,
+            card && !card.copyType ? <CreateFunc key="create" dict={dict} ref="btnCreatFunc" trigger={this.creatFunc}/> : null,
+            <Button key="cancel" onClick={this.editModalCancel}>{dict['header.cancel']}</Button>,
+            <Button key="confirm" type="primary" loading={copying} onClick={this.handleSubmit}>{dict['model.confirm']}</Button>
+          ]}
+          destroyOnClose
+        >
+          <ActionForm
+            dict={dict}
+            card={card}
+            tabs={this.props.tabs}
+            formlist={this.state.formlist}
+            inputSubmit={this.handleSubmit}
+            setting={config.setting}
+            wrappedComponentRef={(inst) => this.actionFormRef = inst}
+          />
+        </Modal>
+        {/* 鎸夐挳浣跨敤绯荤粺瀛樺偍杩囩▼鏃讹紝楠岃瘉淇℃伅妯℃�佹 */}
+        <Modal
+          wrapClassName="model-table-action-verify-modal"
+          title={'楠岃瘉淇℃伅'}
+          visible={profVisible}
+          width={'75vw'}
+          maskClosable={false}
+          style={{minWidth: '900px', maxWidth: '1200px'}}
+          okText={dict['header.submit']}
+          onOk={this.verifySubmit}
+          onCancel={() => { this.setState({ profVisible: false }) }}
+          destroyOnClose
+        >
+          {card && !card.execMode && card.OpenType !== 'excelIn' && card.OpenType !== 'excelOut' ?
+            <VerifyCard
+              floor={this.props.type}
+              card={card}
+              dict={dict}
+              config={config}
+              columns={config.columns}
+              wrappedComponentRef={(inst) => this.verifyRef = inst}
+            /> : null
+          }
+          {card && card.execMode ?
+            <VerifyPrint
+              card={card}
+              dict={dict}
+              columns={config.columns}
+              wrappedComponentRef={(inst) => this.verifyRef = inst}
+            /> : null
+          }
+          {card && card.OpenType === 'excelIn' ?
+            <VerifyExcelIn
+              card={card}
+              dict={dict}
+              columns={config.columns}
+              wrappedComponentRef={(inst) => this.verifyRef = inst}
+            /> : null
+          }
+          {card && card.OpenType === 'excelOut' ?
+            <VerifyExcelOut
+              card={card}
+              dict={dict}
+              wrappedComponentRef={(inst) => this.verifyRef = inst}
+            /> : null
+          }
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default ActionComponent
\ No newline at end of file
diff --git a/src/templates/sharecomponent/actioncomponent/index.scss b/src/templates/sharecomponent/actioncomponent/index.scss
new file mode 100644
index 0000000..1304abf
--- /dev/null
+++ b/src/templates/sharecomponent/actioncomponent/index.scss
@@ -0,0 +1,84 @@
+.model-table-action-list {
+  position: relative;
+  padding: 0px 25px 15px;
+  min-height: 82px;
+  .anticon-question-circle {
+    position: absolute;
+    left: 5px;
+  }
+  > .ant-row {
+    min-height: 80px;
+  }
+  .page-card {
+    display: inline-block;
+    margin: 0px 0px 0px 0px;
+    padding: 15px 10px 0 0;
+    position: relative;
+    div {
+      cursor: move;
+    }
+    .edit {
+      position: absolute;
+      left: 0;
+      top: 0px;
+      color: #1890ff;
+      cursor: pointer;
+      display: none;
+    }
+    .edit.copy {
+      left: 20px;
+      color: #26C281;
+    }
+    .edit.close {
+      left: 40px;
+      color: #ff4d4f;
+    }
+    .edit.profile {
+      left: 60px;
+      color: purple;
+    }
+    button {
+      min-width: 65px;
+      cursor: move;
+      .anticon-table {
+        font-size: 10px;
+        position: absolute;
+        right: 1px;
+        bottom: 0px;
+      }
+    }
+  }
+  .page-card:hover {
+    .edit {
+      display: inline-block;
+    }
+  }
+}
+
+.model-table-action-verify-modal {
+  .ant-modal {
+    top: 50px;
+    padding-bottom: 5px;
+    .ant-modal-body {
+      max-height: calc(100vh - 190px);
+      overflow-y: auto;
+      .ant-empty {
+        margin: 15vh 8px;
+      }
+    }
+    .ant-modal-body::-webkit-scrollbar {
+      width: 7px;
+    }
+    .ant-modal-body::-webkit-scrollbar-thumb {
+      border-radius: 5px;
+      box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
+      background: rgba(0, 0, 0, 0.13);
+    }
+    .ant-modal-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);
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelin/columnform/index.jsx b/src/templates/sharecomponent/actioncomponent/verifyexcelin/columnform/index.jsx
new file mode 100644
index 0000000..b1e6c8f
--- /dev/null
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelin/columnform/index.jsx
@@ -0,0 +1,202 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Select, Button, Input, InputNumber } from 'antd'
+import './index.scss'
+
+
+class UniqueForm extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,         // 瀛楀吀椤�
+    columns: PropTypes.array,       // 鍒楀悕闆嗗悎
+    columnChange: PropTypes.func    // 淇敼鍑芥暟
+  }
+
+  state = {
+    editItem: null, // 缂栬緫鍏冪礌
+    type: 'Nvarchar(50)',
+    locked: false
+  }
+
+  edit = (record) => {
+    this.setState({
+      editItem: record,
+      type: record.type || 'Nvarchar(50)'
+    }, () => {
+      if (!/^Nvarchar/.test(record.type)) {
+        this.props.form.setFieldsValue({
+          min: record.min,
+          max: record.max
+        })
+      }
+    })
+
+    this.props.form.setFieldsValue({
+      Column: record.Column,
+      Text: record.Text,
+      required: record.required,
+      type: record.type
+    })
+    if (record.type === 'Int' || /^Decimal/ig.test(record.type)) {
+      this.setState({
+        locked: true
+      })
+    } else {
+      this.setState({
+        locked: false
+      })
+    }
+  }
+
+  typeChange = (val) => {
+    this.setState({
+      type: val
+    }, () => {
+      if (val === 'Int' || /^Decimal/ig.test(val)) {
+        this.props.form.setFieldsValue({
+          required: 'true',
+        })
+        this.setState({
+          locked: true
+        })
+      } else {
+        this.setState({
+          locked: false
+        })
+      }
+    })
+  }
+
+
+  handleConfirm = () => {
+    // const { columns } = this.props
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    this.props.form.validateFieldsAndScroll((err, values) => {
+      if (!err) {
+        values.uuid = this.state.editItem ? this.state.editItem.uuid : ''
+
+        if (/^Nvarchar/ig.test(values.type)) {
+          values.limit = values.type.match(/\d+/)[0]
+        } else if (/^Decimal/ig.test(values.type)) {
+          values.limit = values.type.match(/\d+/ig)[1]
+        } else {
+          values.limit = ''
+        }
+
+        this.props.columnChange(values)
+        this.setState({
+          editItem: null,
+          locked: false,
+          type: 'Nvarchar(50)'
+        })
+        this.props.form.setFieldsValue({
+          Column: '',
+          Text: '',
+          required: 'true',
+          type: 'Nvarchar(50)'
+        })
+      }
+    })
+  }
+
+  render() {
+    const { getFieldDecorator } = this.props.form
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    let haslimit = !/^Nvarchar/.test(this.state.type)
+
+    return (
+      <Form {...formItemLayout} className="verify-form">
+        <Row gutter={24}>
+          <Col span={7}>
+            <Form.Item label={'Column'}>
+              {getFieldDecorator('Column', {
+                initialValue: '',
+                rules: [
+                  {
+                    required: true,
+                    message: this.props.dict['form.required.input'] + 'Column!'
+                  }
+                ]
+              })(<Input placeholder="" autoComplete="off" />)}
+            </Form.Item>
+          </Col>
+          <Col span={7}>
+            <Form.Item label={'Text'}>
+              {getFieldDecorator('Text', {
+                initialValue: '',
+                rules: [
+                  {
+                    required: true,
+                    message: this.props.dict['form.required.input'] + 'Text!'
+                  }
+                ]
+              })(<Input placeholder="" autoComplete="off" />)}
+            </Form.Item>
+          </Col>
+          <Col span={7}>
+            <Form.Item label={'绫诲瀷'}>
+              {getFieldDecorator('type', {
+                initialValue: 'Nvarchar(50)'
+              })(
+                <Select onChange={this.typeChange}>
+                  <Select.Option value="Nvarchar(10)"> Nvarchar(10) </Select.Option>
+                  <Select.Option value="Nvarchar(20)"> Nvarchar(20) </Select.Option>
+                  <Select.Option value="Nvarchar(50)"> Nvarchar(50) </Select.Option>
+                  <Select.Option value="Nvarchar(100)"> Nvarchar(100) </Select.Option>
+                  <Select.Option value="Nvarchar(512)"> Nvarchar(512) </Select.Option>
+                  <Select.Option value="Int"> Int </Select.Option>
+                  <Select.Option value="Decimal(18,0)"> Decimal(18,0) </Select.Option>
+                  <Select.Option value="Decimal(18,2)"> Decimal(18,2) </Select.Option>
+                  <Select.Option value="Decimal(18,4)"> Decimal(18,4) </Select.Option>
+                  <Select.Option value="Decimal(18,6)"> Decimal(18,6) </Select.Option>
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+          <Col span={3} className="add">
+            <Button onClick={this.handleConfirm} type="primary" className="mk-green">
+              淇濆瓨
+            </Button>
+          </Col>
+          <Col span={7}>
+            <Form.Item label={'鏄惁蹇呭~'}>
+              {getFieldDecorator('required', {
+                initialValue: 'true'
+              })(
+                <Select disabled={this.state.locked}>
+                  <Select.Option value="false"> 鍚� </Select.Option>
+                  <Select.Option value="true"> 鏄� </Select.Option>
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+          {haslimit ? <Col span={7}>
+            <Form.Item label={'鏈�灏忓��'}>
+              {getFieldDecorator('min', {
+                initialValue: ''
+              })(<InputNumber />)}
+            </Form.Item>
+          </Col> : null}
+          {haslimit ? <Col span={7}>
+            <Form.Item label={'鏈�澶у��'}>
+              {getFieldDecorator('max', {
+                initialValue: ''
+              })(<InputNumber />)}
+            </Form.Item>
+          </Col> : null}
+        </Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(UniqueForm)
\ No newline at end of file
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelin/columnform/index.scss b/src/templates/sharecomponent/actioncomponent/verifyexcelin/columnform/index.scss
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelin/columnform/index.scss
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelin/customscript/index.jsx b/src/templates/sharecomponent/actioncomponent/verifyexcelin/customscript/index.jsx
new file mode 100644
index 0000000..cbbd0d8
--- /dev/null
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelin/customscript/index.jsx
@@ -0,0 +1,296 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Input, Button, notification, Modal, Menu, Icon, Tooltip, Radio, Dropdown } from 'antd'
+import moment from 'moment'
+
+import Utils from '@/utils/utils.js'
+import Api from '@/api'
+import './index.scss'
+
+const { TextArea } = Input
+
+class CustomForm extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,         // 瀛楀吀椤�
+    btn: PropTypes.object,          // 鎸夐挳淇℃伅
+    scripts: PropTypes.array,       // 鑷畾涔夎剼鏈垪琛�
+    usefulfields: PropTypes.any,    // 鍙敤瀛楁
+    systemScripts: PropTypes.array, // 绯荤粺鑴氭湰
+    scriptsChange: PropTypes.func   // 琛ㄥ崟
+  }
+
+  state = {
+    editItem: null,
+    usefulfields: null,
+    loading: false,
+    verifySql: ''
+  }
+
+  UNSAFE_componentWillMount () {
+    const {usefulfields, btn} = this.props
+
+    let fields = usefulfields.map(item => item.Column)
+    if (!fields.includes('ID')) {
+      fields.unshift('ID')
+    }
+    if (!fields.includes('BID')) {
+      fields.unshift('BID')
+    }
+
+    let _sql = `Declare @${btn.sheet} table (${usefulfields.map(item => item.Column + ' ' + item.type).join(',')},jskey nvarchar(50) )
+      Declare @UserName nvarchar(50),@FullName nvarchar(50),@ErrorCode nvarchar(50), @retmsg nvarchar(4000)
+      Select @ErrorCode='', @retmsg=''
+    `
+    
+    this.setState({
+      verifySql: _sql,
+      usefulfields: fields.join(', ')
+    })
+  }
+
+  edit = (record) => {
+    this.setState({
+      editItem: record
+    })
+
+    this.props.form.setFieldsValue({
+      sql: record.sql,
+      position: record.position || 'back'
+    })
+  }
+
+  handleConfirm = () => {
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    this.props.form.validateFieldsAndScroll((err, values) => {
+      if (!err) {
+        values.uuid = this.state.editItem ? this.state.editItem.uuid : ''
+
+        let _quot = values.sql.match(/'{1}/g)
+        let _lparen = values.sql.match(/\({1}/g)
+        let _rparen = values.sql.match(/\){1}/g)
+
+        _quot = _quot ? _quot.length : 0
+        _lparen = _lparen ? _lparen.length : 0
+        _rparen = _rparen ? _rparen.length : 0
+
+        if (_quot % 2 !== 0) {
+          notification.warning({
+            top: 92,
+            message: 'sql涓璡'蹇呴』鎴愬鍑虹幇',
+            duration: 5
+          })
+          return
+        } else if (_lparen !== _rparen) {
+          notification.warning({
+            top: 92,
+            message: 'sql涓�()蹇呴』鎴愬鍑虹幇',
+            duration: 5
+          })
+          return
+        } else if (/--/ig.test(values.sql)) {
+          notification.warning({
+            top: 92,
+            message: '鑷畾涔塻ql璇彞涓紝涓嶅彲鍑虹幇瀛楃 -- 锛屾敞閲婅鐢� /*鍐呭*/',
+            duration: 5
+          })
+          return
+        }
+
+        let error = Utils.verifySql(values.sql, 'customscript')
+
+        if (error) {
+          notification.warning({
+            top: 92,
+            message: 'sql涓笉鍙娇鐢�' + error,
+            duration: 5
+          })
+          return
+        }
+
+        let tail = `
+          aaa:
+        `
+
+        let _initsql = ''
+        this.props.scripts.forEach(script => {
+          if (this.state.editItem && this.state.editItem.uuid === script.uuid) return
+          if (script.status === 'false' || script.position !== 'init') return
+
+          _initsql += `
+            ${script.sql}
+            `
+        })
+
+        let param = {
+          func: 's_debug_sql',
+          LText: this.state.verifySql + _initsql + values.sql + tail
+        }
+        param.LText = Utils.formatOptions(param.LText)
+        param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
+        param.secretkey = Utils.encrypt(param.LText, param.timestamp)
+        
+        this.setState({loading: true})
+        Api.getLocalConfig(param).then(res => {
+          if (res.status) {
+            this.setState({
+              loading: false,
+              editItem: null
+            }, () => {
+              this.props.scriptsChange(values)
+            })
+            this.props.form.setFieldsValue({
+              sql: ''
+            })
+          } else {
+            this.setState({loading: false})
+
+            Modal.error({
+              title: res.message
+            })
+          }
+        })
+      }
+    })
+  }
+
+  selectScript = (e) => {
+    const { systemScripts, usefulfields, btn } = this.props
+
+    let option = ''
+    if (e.key === 'default') {
+      let fields = usefulfields.map(col => col.Column).join(',')
+      
+      if (fields) {
+        fields = fields + ','
+      }
+
+      option = {
+        name: '榛樿sql',
+        value: `Insert into ${btn.sheet} (${fields}createuserid,createuser,createstaff,bid)\nSelect ${fields}@userid,@username,@fullname,@BID From @${btn.sheet}`
+      }
+    } else {
+      option = systemScripts[+e.key]
+    }
+
+    let _sql = this.props.form.getFieldValue('sql')
+    if (_sql) {
+      _sql = _sql + ` 
+
+      `
+    }
+
+    _sql = _sql.replace(/\s{6}$/, '')
+    _sql = _sql + `/*${option.name}*/
+    `
+    _sql = _sql.replace(/\s{4}$/, '')
+    _sql = _sql + option.value
+
+    this.props.form.setFieldsValue({
+      sql: _sql
+    })
+  }
+
+  render() {
+    const { systemScripts, btn } = this.props
+    const { usefulfields } = this.state
+    const { getFieldDecorator } = this.props.form
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <Form {...formItemLayout} className="verify-form" id="verifycard2">
+        <Row gutter={24}>
+          {usefulfields ? <Col span={24} className="sqlfield">
+            <Form.Item label={'鍙敤瀛楁'}>
+              {usefulfields}
+            </Form.Item>
+          </Col> : null}
+          <Col span={8} style={{whiteSpace: 'nowrap'}}>
+            <Form.Item style={{marginBottom: 0}} label={
+              <Tooltip placement="bottomLeft" title={'鑷畾涔夎剼鏈笌榛樿sql浣嶇疆鍏崇郴銆�'}>
+                <Icon type="question-circle" style={{color: '#c49f47', marginRight: '5px'}} />
+                鎵ц浣嶇疆
+              </Tooltip>
+            }>
+              {getFieldDecorator('position', {
+                initialValue: 'back'
+              })(
+                <Radio.Group>
+                  <Radio value="init">鍒濆鍖�</Radio>
+                  <Radio value="front">sql鍓�</Radio>
+                  <Radio value="back">sql鍚�</Radio>
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col>
+          <Col span={4} style={{lineHeight: '40px', textAlign: 'center'}}>
+            <Dropdown trigger={['click']} overlayClassName="mk-normal-dropdown" overlay={
+              <Menu onClick={this.selectScript}>
+                <Menu.Item key="default">榛樿sql</Menu.Item>
+                {systemScripts.map((option, i) =>
+                  <Menu.Item key={i} value={option.value}>{option.name}</Menu.Item>
+                )}
+                {systemScripts.map((option, i) =>
+                  <Menu.Item key={i + '1'} value={option.value}>{option.name}</Menu.Item>
+                )}
+              </Menu>
+            }>
+              <span style={{color: '#1890ff', display: 'inline-block', cursor: 'pointer'}}>
+                蹇嵎娣诲姞 <Icon type="down" style={{marginRight: '5px'}} />
+              </span>
+            </Dropdown>
+          </Col>
+          {/* <Col span={8}>
+            <Form.Item style={{marginBottom: 0}} label={
+              <Tooltip placement="bottomLeft" title={'浠庣郴缁熷嚱鏁伴泦涓�夋嫨闇�瑕佺殑鍑芥暟锛屽彲蹇�熸坊鍔犺嚦sql涓��'}>
+                <Icon type="question-circle" style={{color: '#c49f47', marginRight: '5px'}} />
+                蹇嵎娣诲姞
+              </Tooltip>
+            }>
+              <Select value="" onChange={this.selectScript}>
+                {systemScripts.map((option, i) =>
+                  <Select.Option title={option.name} key={i} value={option.value}>
+                    {option.name}
+                  </Select.Option>
+                )}
+              </Select>
+            </Form.Item>
+          </Col> */}
+          <Col span={4} className="add">
+            <Button onClick={this.handleConfirm} loading={this.state.loading} className="mk-green" style={{marginBottom: 15, marginLeft: 40}}>
+              淇濆瓨
+            </Button>
+          </Col>
+          <Col span={8} style={{textAlign: 'right'}}>
+            {btn.sheet ? <span style={{maxWidth: '100%', display: 'inline-block', position: 'relative', top: '20px', whiteSpace: 'nowrap', textOverflow: 'ellipsis', overflow: 'hidden'}}>
+              琛ㄥ悕:  {btn.sheet}
+            </span> : null}
+          </Col>
+          <Col span={24} className="sql">
+            <Form.Item label={'sql'}>
+              {getFieldDecorator('sql', {
+                initialValue: '',
+                rules: [
+                  {
+                    required: true,
+                    message: this.props.dict['form.required.input'] + 'sql!'
+                  }
+                ]
+              })(<TextArea rows={15} />)}
+            </Form.Item>
+          </Col>
+        </Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(CustomForm)
\ No newline at end of file
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelin/customscript/index.scss b/src/templates/sharecomponent/actioncomponent/verifyexcelin/customscript/index.scss
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelin/customscript/index.scss
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelin/index.jsx b/src/templates/sharecomponent/actioncomponent/verifyexcelin/index.jsx
new file mode 100644
index 0000000..a9a815f
--- /dev/null
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelin/index.jsx
@@ -0,0 +1,825 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Tabs, Row, Col, Input, Button, Table, Popconfirm, Icon, notification, Modal, message, InputNumber, Radio } from 'antd'
+import moment from 'moment'
+
+import Api from '@/api'
+import Utils from '@/utils/utils.js'
+
+import UniqueForm from './uniqueform'
+import ColumnForm from './columnform'
+import CustomScript from './customscript'
+import './index.scss'
+
+const { TabPane } = Tabs
+const { confirm } = Modal
+
+class VerifyCard extends Component {
+  static propTpyes = {
+    columns: PropTypes.array,  // 鏄剧ず鍒�
+    dict: PropTypes.object,    // 瀛楀吀椤�
+    card: PropTypes.object,
+  }
+
+  state = {
+    verify: {},
+    systemScripts: [],
+    excelColumns: [
+      {
+        title: 'Column',
+        dataIndex: 'Column',
+        width: '16%',
+        editable: true
+      },
+      {
+        title: 'Text',
+        dataIndex: 'Text',
+        width: '19%',
+        editable: true
+      },
+      {
+        title: '绫诲瀷',
+        dataIndex: 'type',
+        width: '12%',
+        editable: true
+      },
+      {
+        title: '鏄惁蹇呭~',
+        dataIndex: 'required',
+        width: '12%',
+        editable: true,
+        render: (text, record) => record.required === 'true' ? '鏄�' : '鍚�'
+      },
+      {
+        title: '鏈�灏忓��',
+        dataIndex: 'min',
+        width: '12%',
+        editable: true
+      },
+      {
+        title: '鏈�澶у��',
+        dataIndex: 'max',
+        width: '12%',
+        editable: true
+      },
+      {
+        title: '鎿嶄綔',
+        align: 'center',
+        dataIndex: 'operation',
+        render: (text, record) =>
+          (
+            <div>
+              <span className="operation-btn" title={this.props.dict['model.edit']} onClick={() => this.handleEdit(record, 'columns')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
+              <span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'columns', 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
+              <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'columns', 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
+              <Popconfirm
+                title={this.props.dict['header.form.query.delete']}
+                okText={this.props.dict['model.confirm']}
+                cancelText={this.props.dict['header.cancel']}
+                onConfirm={() => this.handleDelete(record, 'columns')
+              }>
+                <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
+              </Popconfirm>
+            </div>
+          )
+      }
+    ],
+    uniqueColumns: [
+      {
+        title: '瀛楁鍚�',
+        dataIndex: 'field',
+        width: '35%'
+      },
+      {
+        title: '鎶ラ敊缂栫爜',
+        dataIndex: 'errorCode',
+        width: '12%'
+      },
+      {
+        title: '楠岃瘉绫诲瀷',
+        dataIndex: 'verifyType',
+        width: '13%',
+        render: (text, record) => record.verifyType === 'logic' ? '閫昏緫楠岃瘉' : '鐗╃悊楠岃瘉'
+      },
+      {
+        title: '鐘舵��',
+        dataIndex: 'status',
+        width: '15%',
+        render: (text, record) => record.status === 'false' ?
+          (
+            <div>
+              {this.props.dict['header.form.status.forbidden']}
+              <Icon style={{marginLeft: '5px'}} type="stop" theme="twoTone" twoToneColor="#ff4d4f" />
+            </div>
+          ) :
+          (
+            <div>
+              {this.props.dict['header.form.status.open']}
+              <Icon style={{marginLeft: '5px'}} type="check-circle" theme="twoTone" twoToneColor="#52c41a" />
+            </div>
+          )
+      },
+      {
+        title: '鎿嶄綔',
+        align: 'center',
+        width: '25%',
+        dataIndex: 'operation',
+        render: (text, record) =>
+          (<div>
+            <span className="operation-btn" title={this.props.dict['model.edit']} onClick={() => this.handleEdit(record, 'unique')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
+            <span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'unique', 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
+            <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'unique', 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
+            <span className="operation-btn" title={this.props.dict['header.form.status.change']} onClick={() => this.handleStatus(record, 'unique')} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
+            <Popconfirm
+              title={this.props.dict['header.form.query.delete']}
+              okText={this.props.dict['model.confirm']}
+              cancelText={this.props.dict['header.cancel']}
+              onConfirm={() => this.handleDelete(record, 'unique')
+            }>
+              <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
+            </Popconfirm>
+          </div>)
+      }
+    ],
+    scriptsColumns: [
+      {
+        title: 'SQL',
+        dataIndex: 'sql',
+        width: '60%'
+      },
+      {
+        title: '鎵ц浣嶇疆',
+        dataIndex: 'position',
+        width: '10%',
+        render: (text, record) => record.position !== 'front' ? 'sql鍚�' : 'sql鍓�'
+      },
+      {
+        title: '鐘舵��',
+        dataIndex: 'status',
+        width: '10%',
+        render: (text, record) => record.status === 'false' ?
+          (
+            <div>
+              {this.props.dict['header.form.status.forbidden']}
+              <Icon style={{marginLeft: '5px'}} type="stop" theme="twoTone" twoToneColor="#ff4d4f" />
+            </div>
+          ) :
+          (
+            <div>
+              {this.props.dict['header.form.status.open']}
+              <Icon style={{marginLeft: '5px'}} type="check-circle" theme="twoTone" twoToneColor="#52c41a" />
+            </div>
+          )
+      },
+      {
+        title: '鎿嶄綔',
+        align: 'center',
+        width: '20%',
+        dataIndex: 'operation',
+        render: (text, record) =>
+          (<div>
+            <span className="operation-btn" title={this.props.dict['model.edit']} onClick={() => this.handleEdit(record, 'scripts')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
+            <span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'scripts', 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
+            <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'scripts', 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
+            <span className="operation-btn" title={this.props.dict['header.form.status.change']} onClick={() => this.handleStatus(record, 'scripts')} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
+            <Popconfirm
+              title={this.props.dict['header.form.query.delete']}
+              okText={this.props.dict['model.confirm']}
+              cancelText={this.props.dict['header.cancel']}
+              onConfirm={() => this.handleDelete(record, 'scripts')
+            }>
+              <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
+            </Popconfirm>
+          </div>)
+      }
+    ]
+  }
+
+  UNSAFE_componentWillMount() {
+    let _verify = this.props.card.verify || {}
+
+    let _columns = _verify.columns || []
+    _columns = _columns.map(col => {
+      col.required = col.required || 'true'
+      col.type = col.type || 'Nvarchar(50)'
+      
+      if (/^Nvarchar/ig.test(col.type)) {
+        col.limit = col.type.match(/\d+/)[0]
+      } else if (/^Decimal/ig.test(col.type)) {
+        col.limit = col.type.match(/\d+/ig)[1]
+      } else {
+        col.limit = ''
+      }
+
+      return col
+    })
+
+    this.setState({
+      verify: {
+        ..._verify,
+        default: _verify.default || 'true',
+        sheet: _verify.sheet || 'Sheet1',
+        range: _verify.range || 0,
+        columns: _columns,
+        scripts: _verify.scripts || [],
+        uniques: _verify.uniques || []
+      }
+    })
+  }
+
+  componentDidMount () {
+    let _scriptSql = `Select distinct func+Remark as funcname,longparam, s.Sort from聽 s_custom_script s inner join (select OpenID from sapp where ID=@Appkey@) p on s.openid = case when s.appkey='' then s.openid else p.OpenID end order by s.Sort`
+
+    _scriptSql = Utils.formatOptions(_scriptSql)
+
+    let _sParam = {
+      func: 'sPC_Get_SelectedList',
+      LText: _scriptSql,
+      obj_name: 'data',
+      arr_field: 'funcname,longparam'
+    }
+    
+    _sParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
+    _sParam.secretkey = Utils.encrypt(_sParam.LText, _sParam.timestamp)
+    
+    Api.getSystemConfig(_sParam).then(res => {
+      if (res.status) {
+        this.setState({
+          systemScripts: res.data.map(item => {
+            return {
+              name: item.funcname,
+              value: Utils.formatOptions(item.longparam, true)
+            }
+          })
+        })
+      } else {
+        notification.warning({
+          top: 92,
+          message: res.message,
+          duration: 5
+        })
+      }
+    })
+  }
+
+  columnFieldInput = () => {
+    const { columns } = this.props
+    const { verify } = this.state
+
+    let _columns = JSON.parse(JSON.stringify(verify.columns))
+
+    let _cols = _columns.map(col => col.Column )
+
+    columns.forEach(col => {
+      if (col.field && !_cols.includes(col.field)) {
+        let _type = 'Nvarchar(50)'
+        let _limit = '50'
+        if (col.type === 'number' && col.decimal === 0) {
+          _type = 'Int'
+          _limit = ''
+        } else if (col.type === 'number') {
+          _type = 'Decimal(18,' + col.decimal + ')'
+          _limit = col.decimal
+        }
+
+        let _cell = {
+          uuid: col.uuid,
+          Column: col.field,
+          Text: col.label,
+          type: _type,
+          limit: _limit,
+          required: 'true'
+        }
+
+        if (_type !== 'Nvarchar(50)') {
+          _cell.min = 0
+          _cell.max = 999999
+        }
+
+        _columns.push(_cell)
+      }
+    })
+
+    this.setState({
+      verify: {
+        ...verify,
+        columns: _columns
+      }
+    })
+  }
+
+  columnChange = (values) => {
+    let verify = JSON.parse(JSON.stringify(this.state.verify))
+
+    if (values.uuid) {
+      verify.columns = verify.columns.map(item => {
+        if (item.uuid === values.uuid) {
+          return values
+        } else {
+          return item
+        }
+      })
+    } else {
+      values.uuid = Utils.getuuid()
+      verify.columns.push(values)
+    }
+
+    this.setState({
+      verify: verify
+    })
+  }
+
+  uniqueChange = (values) => {
+    let verify = JSON.parse(JSON.stringify(this.state.verify))
+
+    if (values.uuid) {
+      verify.uniques = verify.uniques.map(item => {
+        if (item.uuid === values.uuid) {
+          return values
+        } else {
+          return item
+        }
+      })
+    } else {
+      values.uuid = Utils.getuuid()
+      verify.uniques.push(values)
+    }
+
+    this.setState({
+      verify: verify
+    })
+  }
+
+  scriptsChange = (values) => {
+    let verify = JSON.parse(JSON.stringify(this.state.verify))
+
+    if (values.uuid) {
+      verify.scripts = verify.scripts.map(item => {
+        if (item.uuid === values.uuid) {
+          return values
+        } else {
+          return item
+        }
+      })
+    } else {
+      values.uuid = Utils.getuuid()
+      verify.scripts.push(values)
+    }
+
+    this.setState({
+      verify: verify
+    })
+  }
+
+  handleDelete = (record, type) => {
+    const { verify } = this.state
+
+    if (type === 'columns') {
+      verify.columns = verify.columns.filter(item => item.uuid !== record.uuid)
+    } else if (type === 'scripts') {
+      verify.scripts = verify.scripts.filter(item => item.uuid !== record.uuid)
+    } else if (type === 'unique') {
+      verify.uniques = verify.uniques.filter(item => item.uuid !== record.uuid)
+    }
+
+    this.setState({ verify: verify })
+  }
+
+  handleEdit = (record, type) => {
+    if (type === 'columns') {
+      this.columnForm.edit(record)
+    } else if (type === 'scripts') {
+      this.scriptsForm.edit(record)
+    } else if (type === 'unique') {
+      this.uniqueForm.edit(record)
+    }
+
+    let node = document.getElementById('verify-excel-box-tab').parentNode
+
+    if (node && node.scrollTop) {
+      let inter = Math.ceil(node.scrollTop / 10)
+
+      let timer = setInterval(() => {
+        if (node.scrollTop - inter > 0) {
+          node.scrollTop = node.scrollTop - inter
+        } else {
+          node.scrollTop = 0
+          clearInterval(timer)
+        }
+      }, 10)
+    }
+  }
+
+  handleStatus = (record, type) => {
+    let verify = JSON.parse(JSON.stringify(this.state.verify))
+    record.status = record.status === 'false' ? 'true' : 'false'
+
+    if (type === 'scripts') {
+      verify.scripts = verify.scripts.map(item => {
+        if (item.uuid === record.uuid) {
+          return record
+        } else {
+          return item
+        }
+      })
+    } else if (type === 'unique') {
+      verify.uniques = verify.uniques.map(item => {
+        if (item.uuid === record.uuid) {
+          return record
+        } else {
+          return item
+        }
+      })
+    }
+
+    this.setState({
+      verify: verify
+    })
+  }
+
+  handleUpDown = (record, type, direction) => {
+    let verify = JSON.parse(JSON.stringify(this.state.verify))
+    let index = 0
+
+    if (type === 'columns') {
+      verify.columns = verify.columns.filter((item, i) => {
+        if (item.uuid === record.uuid) {
+          index = i
+        }
+
+        return item.uuid !== record.uuid
+      })
+      if ((index === 0 && direction === 'up') || (index === verify.columns.length && direction === 'down')) {
+        return
+      }
+
+      if (direction === 'up') {
+        verify.columns.splice(index - 1, 0, record)
+      } else {
+        verify.columns.splice(index + 1, 0, record)
+      }
+    } else if (type === 'unique') {
+      verify.uniques = verify.uniques.filter((item, i) => {
+        if (item.uuid === record.uuid) {
+          index = i
+        }
+
+        return item.uuid !== record.uuid
+      })
+      if ((index === 0 && direction === 'up') || (index === verify.uniques.length && direction === 'down')) {
+        return
+      }
+
+      if (direction === 'up') {
+        verify.uniques.splice(index - 1, 0, record)
+      } else {
+        verify.uniques.splice(index + 1, 0, record)
+      }
+    } else if (type === 'scripts') {
+      verify.scripts = verify.scripts.filter((item, i) => {
+        if (item.uuid === record.uuid) {
+          index = i
+        }
+
+        return item.uuid !== record.uuid
+      })
+      if ((index === 0 && direction === 'up') || (index === verify.scripts.length && direction === 'down')) {
+        return
+      }
+
+      if (direction === 'up') {
+        verify.scripts.splice(index - 1, 0, record)
+      } else {
+        verify.scripts.splice(index + 1, 0, record)
+      }
+    }
+
+    this.setState({
+      verify: verify
+    })
+  }
+
+  handleConfirm = () => {
+    const { verify } = this.state
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          let _verify = {...verify, ...values}
+
+          let cols = _verify.columns.map(col => col.Column)
+          cols = Array.from(new Set(cols))
+
+          if (_verify.columns.length === 0) {
+            notification.warning({
+              top: 92,
+              message: '璇疯缃瓻xcel鍒楀瓧娈�!',
+              duration: 5
+            })
+            return
+          } else if (_verify.columns.length > cols.length) {
+            notification.warning({
+              top: 92,
+              message: 'Excel鍒楀瓧娈靛悕锛屼笉鍙噸澶�!',
+              duration: 5
+            })
+            return
+          } else if (_verify.range === 1) {
+            let tEmptys = _verify.columns.filter(op => !op.Text)
+            if (tEmptys.length > 0) {
+              notification.warning({
+                top: 92,
+                message: '蹇界暐棣栬鏃讹紝浼氫娇鐢═ext鍊兼牎楠孍xcel棣栬鍐呭锛孴ext鍊间笌Excel琛ㄩ琛屽唴瀹圭浉鍚岋紝涓斿潎涓嶅彲涓虹┖锛�',
+                duration: 5
+              })
+              return
+            }
+          }
+
+          let _loading = false
+          if (this.columnForm && this.columnForm.state.editItem) {
+            _loading = true
+          } else if (this.scriptsForm && this.scriptsForm.state.editItem) {
+            _loading = true
+          } else if (this.uniqueForm && this.uniqueForm.state.editItem) {
+            _loading = true
+          }
+
+          if (this.scriptsForm && this.scriptsForm.props.form.getFieldValue('sql')) {
+            _loading = true
+          }
+
+          if (_loading) {
+            confirm({
+              content: `瀛樺湪鏈繚瀛橀」锛岀‘瀹氭彁浜ゅ悧锛焋,
+              okText: this.props.dict['model.confirm'],
+              cancelText: this.props.dict['header.cancel'],
+              onOk() {
+                resolve(_verify)
+              },
+              onCancel() {}
+            })
+          } else {
+            resolve(_verify)
+          }
+        } else {
+          notification.warning({
+            top: 92,
+            message: '璇疯缃瓻xcel琛ㄥ悕!',
+            duration: 5
+          })
+        }
+      })
+    })
+  }
+
+  onOptionChange = (e, key) => {
+    const { verify } = this.state
+    let value = e.target.value
+
+    this.setState({
+      verify: {...verify, default: value}
+    })
+  }
+
+  showError = (errorType) => {
+    if (errorType === 'S') {
+      notification.success({
+        top: 92,
+        message: '鎵ц鎴愬姛锛�',
+        duration: 2
+      })
+    } else if (errorType === 'Y') {
+      Modal.success({
+        title: '鎵ц鎴愬姛锛�'
+      })
+    } else if (errorType === 'F') {
+      notification.error({
+        className: 'notification-custom-error',
+        top: 92,
+        message: '鎵ц澶辫触锛�',
+        duration: 10
+      })
+    } else if (errorType === 'N') {
+      notification.error({
+        top: 92,
+        message: '鎵ц澶辫触锛�',
+        duration: 10
+      })
+    } else if (errorType === 'E') {
+      Modal.error({
+        title: '鎵ц澶辫触锛�'
+      })
+    } else if (errorType === 'NM') {
+      message.error('鎵ц澶辫触锛�')
+    }
+  }
+
+  timeChange = (val, type) => {
+    const { verify } = this.state
+
+    this.setState({
+      verify: {...verify, [type]: val}
+    })
+  }
+
+  render() {
+    const { card } = this.props
+    const { getFieldDecorator } = this.props.form
+    const { verify, excelColumns, scriptsColumns, uniqueColumns } = this.state
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <div id="verify-excel-box-tab">
+        <Tabs defaultActiveKey="1" className="verify-card-box" onChange={this.tabchange}>
+          <TabPane tab="鍩虹楠岃瘉" key="1">
+            <Form {...formItemLayout}>
+              <Row gutter={24}>
+                <Col span={8}>
+                  <Form.Item label={'Excel琛ㄥ悕'}>
+                    {getFieldDecorator('sheet', {
+                      initialValue: verify.sheet || '',
+                      rules: [
+                        {
+                          required: true,
+                          message: this.props.dict['form.required.input'] + this.props.dict['header.form.tablename'] + '!'
+                        }
+                      ]
+                    })(<Input placeholder="" autoComplete="off" />)}
+                  </Form.Item>
+                </Col>
+                <Col span={8}>
+                  <Form.Item label={'蹇界暐琛�'}>
+                    {getFieldDecorator('range', {
+                      initialValue: verify.range || 0
+                    })(<InputNumber min={0} max={100} precision={0} />)}
+                  </Form.Item>
+                </Col>
+                {card.intertype === 'inner' && !card.innerFunc ? <Col span={8}>
+                  <Form.Item label={'榛樿sql'}>
+                    <Radio.Group value={verify.default} onChange={this.onOptionChange}>
+                      <Radio value="true">鎵ц</Radio>
+                      <Radio value="false">涓嶆墽琛�</Radio>
+                    </Radio.Group>
+                  </Form.Item>
+                </Col> : null}
+              </Row>
+            </Form>
+          </TabPane>
+          <TabPane tab="Excel鍒楄缃�" key="2x">
+            <ColumnForm
+              dict={this.props.dict}
+              columns={verify.columns}
+              columnChange={this.columnChange}
+              wrappedComponentRef={(inst) => this.columnForm = inst}
+            />
+            <Button className="excel-col-add mk-green" title="娣诲姞鏄剧ず鍒楀瓧娈�" onClick={this.columnFieldInput}>
+              蹇嵎娣诲姞
+            </Button>
+            <Table
+              bordered
+              rowKey="uuid"
+              className="custom-table"
+              dataSource={verify.columns}
+              columns={excelColumns}
+              pagination={false}
+            />
+          </TabPane>
+          {card.intertype === 'inner' && !card.innerFunc ? <TabPane tab="鍞竴鎬ч獙璇�" key="3">
+            <UniqueForm
+              fields={verify.columns}
+              dict={this.props.dict}
+              uniqueChange={this.uniqueChange}
+              wrappedComponentRef={(inst) => this.uniqueForm = inst}
+            />
+            <Table
+              bordered
+              rowKey="uuid"
+              className="custom-table"
+              dataSource={verify.uniques}
+              columns={uniqueColumns}
+              pagination={false}
+            />
+          </TabPane> : null}
+          {card.intertype === 'inner' && !card.innerFunc ? <TabPane tab="鑷畾涔夎剼鏈�" key="6">
+            <CustomScript
+              dict={this.props.dict}
+              btn={this.props.card}
+              usefulfields={verify.columns}
+              scripts={verify.scripts}
+              systemScripts={this.state.systemScripts}
+              scriptsChange={this.scriptsChange}
+              wrappedComponentRef={(inst) => this.scriptsForm = inst}
+            />
+            <Table
+              bordered
+              rowKey="uuid"
+              className="custom-table"
+              dataSource={verify.scripts}
+              columns={scriptsColumns}
+              pagination={false}
+            />
+          </TabPane> : null}
+          <TabPane tab="淇℃伅鎻愮ず" key="7">
+            <Form {...formItemLayout}>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> S </span>
+                    <Button onClick={() => {this.showError('S')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+                <Col span={8}>
+                  <Form.Item label={'鍋滅暀鏃堕棿'}>
+                    <InputNumber defaultValue={verify.stime || 2} min={1} max={10000} precision={0} onChange={(val) => {this.timeChange(val, 'stime')}} />
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> Y </span>
+                    <Button onClick={() => {this.showError('Y')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> N </span>
+                    <Button onClick={() => {this.showError('N')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+                <Col span={8}>
+                  <Form.Item label={'鍋滅暀鏃堕棿'}>
+                    <InputNumber defaultValue={verify.ntime || 10} min={1} max={10000} precision={0} onChange={(val) => {this.timeChange(val, 'ntime')}} />
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> F </span>
+                    <Button onClick={() => {this.showError('F')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+                <Col span={8}>
+                  <Form.Item label={'鍋滅暀鏃堕棿'}>
+                    <InputNumber defaultValue={verify.ftime || 10} min={1} max={10000} precision={0} onChange={(val) => {this.timeChange(val, 'ftime')}} />
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> E </span>
+                    <Button onClick={() => {this.showError('E')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> NM </span>
+                    <Button onClick={() => {this.showError('NM')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> -1 </span>
+                    涓嶆彁绀�
+                  </Form.Item>
+                </Col>
+              </Row>
+            </Form>
+          </TabPane>
+        </Tabs>
+      </div>
+    )
+  }
+}
+
+export default Form.create()(VerifyCard)
\ No newline at end of file
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelin/index.scss b/src/templates/sharecomponent/actioncomponent/verifyexcelin/index.scss
new file mode 100644
index 0000000..0831874
--- /dev/null
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelin/index.scss
@@ -0,0 +1,70 @@
+.verify-card-box {
+  .ant-tabs-nav-scroll {
+    text-align: center;
+  }
+  .ant-tabs-content {
+    min-height: 40vh;
+  }
+  table tr td {
+    word-wrap: break-word;
+    word-break: break-word;
+  }
+  .ant-input-number {
+    width: 100%;
+  }
+  .verify-form {
+    .sql {
+      .ant-col-sm-8 {
+        width: 10.5%;
+      }
+      .ant-col-sm-16 {
+        width: 89.5%;
+        padding-top: 4px;
+      }
+    }
+    .sqlfield {
+      .ant-form-item {
+        margin-bottom: 5px;
+      }
+      .ant-form-item-control {
+        line-height: 24px;
+      }
+      .ant-form-item-label {
+        line-height: 25px;
+      }
+      .ant-form-item-children {
+        line-height: 22px;
+      }
+      .ant-col-sm-8 {
+        width: 10.5%;
+      }
+      .ant-col-sm-16 {
+        width: 89.5%;
+      }
+    }
+    .add {
+      padding-top: 4px;
+    }
+  }
+  .custom-table .ant-empty {
+    margin: 20px 8px!important;
+  }
+  .errorval {
+    display: inline-block;
+    width: 30px;
+  }
+  .operation-btn {
+    display: inline-block;
+    font-size: 16px;
+    padding: 0 5px;
+    cursor: pointer;
+  }
+  .ant-tabs-tabpane {
+    position: relative;
+    .excel-col-add {
+      position: absolute;
+      right: 0;
+      top: 90px;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelin/uniqueform/index.jsx b/src/templates/sharecomponent/actioncomponent/verifyexcelin/uniqueform/index.jsx
new file mode 100644
index 0000000..38ea99a
--- /dev/null
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelin/uniqueform/index.jsx
@@ -0,0 +1,149 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Select, Button } from 'antd'
+import './index.scss'
+
+
+class UniqueForm extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,       // 瀛楀吀椤�
+    fields: PropTypes.array,      // 琛ㄥ崟瀛楁
+    uniqueChange: PropTypes.func  // 淇敼鍑芥暟
+  }
+
+  state = {
+    editItem: null // 缂栬緫鍏冪礌
+  }
+
+  edit = (record) => {
+    this.setState({
+      editItem: record
+    })
+
+    this.props.form.setFieldsValue({
+      field: record.field.split(','),
+      errorCode: record.errorCode,
+      verifyType: record.verifyType || 'physical'
+    })
+  }
+
+
+  handleConfirm = () => {
+    const { fields } = this.props
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    this.props.form.validateFieldsAndScroll((err, values) => {
+      if (!err) {
+        values.uuid = this.state.editItem ? this.state.editItem.uuid : ''
+        values.fieldlabel = values.field.map(field => {
+          let item = fields.filter(cell => cell.Column === field)[0]
+          let label = ''
+          if (item) {
+            label = item.Text
+          }
+          return label
+        })
+
+        values.fieldlabel = values.fieldlabel.join(',')
+        values.field = values.field.join(',')
+
+        this.setState({
+          editItem: null
+        }, () => {
+          this.props.uniqueChange(values)
+        })
+        this.props.form.setFieldsValue({
+          field: [],
+        })
+      }
+    })
+  }
+
+  render() {
+    const { getFieldDecorator } = this.props.form
+    const { fields } = this.props
+
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <Form {...formItemLayout} className="verify-form" id="verifycard1">
+        <Row gutter={24}>
+          <Col span={8}>
+            <Form.Item label={'鍒楀悕'}>
+              {getFieldDecorator('field', {
+                initialValue: [],
+                rules: [
+                  {
+                    required: true,
+                    message: this.props.dict['form.required.select'] + '鍒楀悕!'
+                  }
+                ]
+              })(
+                <Select
+                  mode="multiple"
+                >
+                  {fields.map(item => (
+                    <Select.Option key={item.uuid} value={item.Column}>{item.Text}</Select.Option>
+                  ))}
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+          <Col span={6}>
+            <Form.Item label={'鎶ラ敊缂栫爜'}>
+              {getFieldDecorator('errorCode', {
+                initialValue: 'E',
+                rules: [
+                  {
+                    required: true,
+                    message: this.props.dict['form.required.select'] + '鎶ラ敊缂栫爜!'
+                  }
+                ]
+              })(
+                <Select>
+                  <Select.Option value="E"> E </Select.Option>
+                  <Select.Option value="N"> N </Select.Option>
+                  <Select.Option value="F"> F </Select.Option>
+                  <Select.Option value="NM"> NM </Select.Option>
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+          <Col span={6}>
+            <Form.Item label={'楠岃瘉绫诲瀷'}>
+              {getFieldDecorator('verifyType', {
+                initialValue: 'physical',
+                rules: [
+                  {
+                    required: true,
+                    message: this.props.dict['form.required.select'] + '楠岃瘉绫诲瀷!'
+                  }
+                ]
+              })(
+                <Select>
+                  <Select.Option value="physical"> 鐗╃悊楠岃瘉 </Select.Option>
+                  <Select.Option value="logic"> 閫昏緫楠岃瘉 </Select.Option>
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+          <Col span={4} className="add">
+            <Button onClick={this.handleConfirm} className="mk-green">
+              淇濆瓨
+            </Button>
+          </Col>
+        </Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(UniqueForm)
\ No newline at end of file
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelin/uniqueform/index.scss b/src/templates/sharecomponent/actioncomponent/verifyexcelin/uniqueform/index.scss
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelin/uniqueform/index.scss
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelout/columnform/index.jsx b/src/templates/sharecomponent/actioncomponent/verifyexcelout/columnform/index.jsx
new file mode 100644
index 0000000..049e657
--- /dev/null
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelout/columnform/index.jsx
@@ -0,0 +1,127 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Button, Input, InputNumber } from 'antd'
+import './index.scss'
+
+class UniqueForm extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,         // 瀛楀吀椤�
+    columns: PropTypes.array,       // 鍒楀悕闆嗗悎
+    columnChange: PropTypes.func    // 淇敼鍑芥暟
+  }
+
+  state = {
+    editItem: null // 缂栬緫鍏冪礌
+  }
+
+  edit = (record) => {
+    this.setState({
+      editItem: record
+    })
+
+    this.props.form.setFieldsValue({
+      Column: record.Column,
+      Text: record.Text,
+      Width: record.Width,
+    })
+  }
+
+
+  handleConfirm = () => {
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    this.props.form.validateFieldsAndScroll((err, values) => {
+      if (!err) {
+        values.uuid = this.state.editItem ? this.state.editItem.uuid : ''
+
+        this.props.columnChange(values)
+        this.setState({
+          editItem: null
+        })
+        this.props.form.setFieldsValue({
+          Column: '',
+          Text: '',
+          Width: 20,
+        })
+      }
+    })
+  }
+
+  render() {
+    const { getFieldDecorator } = this.props.form
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <Form {...formItemLayout} className="verify-form">
+        <Row gutter={24}>
+          <Col span={7}>
+            <Form.Item label={'Column'}>
+              {getFieldDecorator('Column', {
+                initialValue: '',
+                rules: [
+                  {
+                    required: true,
+                    message: this.props.dict['form.required.input'] + 'Column!'
+                  }
+                ]
+              })(<Input placeholder="" autoComplete="off" />)}
+            </Form.Item>
+          </Col>
+          <Col span={7}>
+            <Form.Item label={'Text'}>
+              {getFieldDecorator('Text', {
+                initialValue: '',
+                rules: [
+                  {
+                    required: true,
+                    message: this.props.dict['form.required.input'] + 'Text!'
+                  }
+                ]
+              })(<Input placeholder="" autoComplete="off" />)}
+            </Form.Item>
+          </Col>
+          <Col span={7}>
+            <Form.Item label={'Width'}>
+              {getFieldDecorator('Width', {
+                initialValue: 20,
+                rules: [
+                  {
+                    required: true,
+                    message: this.props.dict['form.required.input'] + 'Width!'
+                  }
+                ]
+              })(<InputNumber min={5} max={200} precision={0} />)}
+            </Form.Item>
+          </Col>
+          <Col span={3} className="add">
+            <Button onClick={this.handleConfirm} type="primary" className="mk-green">
+              淇濆瓨
+            </Button>
+          </Col>
+          {/* <Col span={7}>
+            <Form.Item label={'绫诲瀷'}>
+              {getFieldDecorator('type', {
+                initialValue: 'text'
+              })(
+                <Select onChange={this.typeChange}>
+                  <Select.Option value="text"> text </Select.Option>
+                  <Select.Option value="number"> number </Select.Option>
+                </Select>
+              )}
+            </Form.Item>
+          </Col> */}
+        </Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(UniqueForm)
\ No newline at end of file
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelout/columnform/index.scss b/src/templates/sharecomponent/actioncomponent/verifyexcelout/columnform/index.scss
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelout/columnform/index.scss
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx b/src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx
new file mode 100644
index 0000000..cd33cc4
--- /dev/null
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx
@@ -0,0 +1,339 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Tabs, Row, Col, Button, Table, Popconfirm, Icon, notification, Modal, message, InputNumber } from 'antd'
+
+import Utils from '@/utils/utils.js'
+
+import ColumnForm from './columnform'
+import './index.scss'
+
+const { TabPane } = Tabs
+
+class VerifyCard extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,    // 瀛楀吀椤�
+    card: PropTypes.object,
+  }
+
+  state = {
+    verify: {},
+    excelColumns: [
+      {
+        title: 'Column',
+        dataIndex: 'Column',
+        width: '25%'
+      },
+      {
+        title: 'Text',
+        dataIndex: 'Text',
+        width: '25%'
+      },
+      {
+        title: 'Width',
+        dataIndex: 'Width',
+        width: '25%'
+      },
+      {
+        title: '鎿嶄綔',
+        align: 'center',
+        dataIndex: 'operation',
+        render: (text, record) =>
+          (
+            <div>
+              <span className="operation-btn" title={this.props.dict['model.edit']} onClick={() => this.handleEdit(record, 'columns')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
+              <span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'columns', 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
+              <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'columns', 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
+              <Popconfirm
+                title={this.props.dict['header.form.query.delete']}
+                okText={this.props.dict['model.confirm']}
+                cancelText={this.props.dict['header.cancel']}
+                onConfirm={() => this.handleDelete(record, 'columns')
+              }>
+                <span style={{color: '#1890ff', cursor: 'pointer'}}><Icon type="delete" /></span>
+              </Popconfirm>
+            </div>
+          )
+      }
+    ]
+  }
+
+  UNSAFE_componentWillMount() {
+    let _verify = this.props.card.verify || {}
+
+    let _columns = _verify.columns || []
+    _columns = _columns.map(col => {
+      col.Width = col.Width || 20
+      
+      return col
+    })
+
+    this.setState({
+      verify: {
+        ..._verify,
+        columns: _columns,
+      }
+    })
+  }
+
+  columnChange = (values) => {
+    let verify = JSON.parse(JSON.stringify(this.state.verify))
+
+    if (values.uuid) {
+      verify.columns = verify.columns.map(item => {
+        if (item.uuid === values.uuid) {
+          return values
+        } else {
+          return item
+        }
+      })
+    } else {
+      values.uuid = Utils.getuuid()
+      verify.columns.push(values)
+    }
+
+    this.setState({
+      verify: verify
+    })
+  }
+
+  handleDelete = (record, type) => {
+    const { verify } = this.state
+
+    verify.columns = verify.columns.filter(item => item.uuid !== record.uuid)
+
+    this.setState({ verify: verify })
+  }
+
+  handleEdit = (record, type) => {
+    this.columnForm.edit(record)
+
+    let node = document.getElementById('verify-excelout-box-tab').parentNode
+
+    if (node && node.scrollTop) {
+      let inter = Math.ceil(node.scrollTop / 10)
+
+      let timer = setInterval(() => {
+        if (node.scrollTop - inter > 0) {
+          node.scrollTop = node.scrollTop - inter
+        } else {
+          node.scrollTop = 0
+          clearInterval(timer)
+        }
+      }, 10)
+    }
+  }
+
+  handleUpDown = (record, type, direction) => {
+    let verify = JSON.parse(JSON.stringify(this.state.verify))
+    let index = 0
+
+    verify.columns = verify.columns.filter((item, i) => {
+      if (item.uuid === record.uuid) {
+        index = i
+      }
+
+      return item.uuid !== record.uuid
+    })
+    if ((index === 0 && direction === 'up') || (index === verify.columns.length && direction === 'down')) {
+      return
+    }
+
+    if (direction === 'up') {
+      verify.columns.splice(index - 1, 0, record)
+    } else {
+      verify.columns.splice(index + 1, 0, record)
+    }
+
+    this.setState({
+      verify: verify
+    })
+  }
+
+  showError = (errorType) => {
+    if (errorType === 'S') {
+      notification.success({
+        top: 92,
+        message: '鎵ц鎴愬姛锛�',
+        duration: 2
+      })
+    } else if (errorType === 'Y') {
+      Modal.success({
+        title: '鎵ц鎴愬姛锛�'
+      })
+    } else if (errorType === 'F') {
+      notification.error({
+        className: 'notification-custom-error',
+        top: 92,
+        message: '鎵ц澶辫触锛�',
+        duration: 10
+      })
+    } else if (errorType === 'N') {
+      notification.error({
+        top: 92,
+        message: '鎵ц澶辫触锛�',
+        duration: 10
+      })
+    } else if (errorType === 'E') {
+      Modal.error({
+        title: '鎵ц澶辫触锛�'
+      })
+    } else if (errorType === 'NM') {
+      message.error('鎵ц澶辫触锛�')
+    }
+  }
+
+  timeChange = (val, type) => {
+    const { verify } = this.state
+
+    this.setState({
+      verify: {...verify, [type]: val}
+    })
+  }
+
+  handleConfirm = () => {
+    let verify = JSON.parse(JSON.stringify(this.state.verify))
+    
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      let _cols = verify.columns.map(col => col.Column)
+      let _vcols = Array.from(new Set(_cols))
+
+      if (_cols.length > _vcols.length) {
+        notification.warning({
+          top: 92,
+          message: 'Excel鍒楀瓧娈靛悕锛屼笉鍙噸澶�!',
+          duration: 5
+        })
+        
+        return
+      }
+
+      resolve(verify)
+    })
+  }
+
+  render() {
+    const { verify, excelColumns } = this.state
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <div id="verify-excelout-box-tab">
+        <Tabs defaultActiveKey="1" className="verify-card-box" onChange={this.tabchange}>
+          <TabPane tab="Excel瀵煎嚭鍒�" key="1">
+            <ColumnForm
+              dict={this.props.dict}
+              columnChange={this.columnChange}
+              wrappedComponentRef={(inst) => this.columnForm = inst}
+            />
+            <Table
+              bordered
+              rowKey="uuid"
+              className="custom-table"
+              dataSource={verify.columns}
+              columns={excelColumns}
+              pagination={false}
+            />
+          </TabPane>
+          <TabPane tab="淇℃伅鎻愮ず" key="7">
+            <Form {...formItemLayout}>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> S </span>
+                    <Button onClick={() => {this.showError('S')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+                <Col span={8}>
+                  <Form.Item label={'鍋滅暀鏃堕棿'}>
+                    <InputNumber defaultValue={verify.stime || 2} min={1} max={10000} precision={0} onChange={(val) => {this.timeChange(val, 'stime')}} />
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> Y </span>
+                    <Button onClick={() => {this.showError('Y')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> N </span>
+                    <Button onClick={() => {this.showError('N')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+                <Col span={8}>
+                  <Form.Item label={'鍋滅暀鏃堕棿'}>
+                    <InputNumber defaultValue={verify.ntime || 10} min={1} max={10000} precision={0} onChange={(val) => {this.timeChange(val, 'ntime')}} />
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> F </span>
+                    <Button onClick={() => {this.showError('F')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+                <Col span={8}>
+                  <Form.Item label={'鍋滅暀鏃堕棿'}>
+                    <InputNumber defaultValue={verify.ftime || 10} min={1} max={10000} precision={0} onChange={(val) => {this.timeChange(val, 'ftime')}} />
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> E </span>
+                    <Button onClick={() => {this.showError('E')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> NM </span>
+                    <Button onClick={() => {this.showError('NM')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> -1 </span>
+                    涓嶆彁绀�
+                  </Form.Item>
+                </Col>
+              </Row>
+            </Form>
+          </TabPane>
+        </Tabs>
+      </div>
+    )
+  }
+}
+
+export default Form.create()(VerifyCard)
\ No newline at end of file
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelout/index.scss b/src/templates/sharecomponent/actioncomponent/verifyexcelout/index.scss
new file mode 100644
index 0000000..017545b
--- /dev/null
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelout/index.scss
@@ -0,0 +1,62 @@
+.verify-card-box {
+  .ant-tabs-nav-scroll {
+    text-align: center;
+  }
+  .ant-tabs-content {
+    min-height: 40vh;
+  }
+  table tr td {
+    word-wrap: break-word;
+    word-break: break-word;
+  }
+  .ant-input-number {
+    width: 100%;
+  }
+  .verify-form {
+    .sql {
+      .ant-col-sm-8 {
+        width: 10.5%;
+      }
+      .ant-col-sm-16 {
+        width: 89.5%;
+        padding-top: 4px;
+      }
+    }
+    .sqlfield {
+      .ant-form-item {
+        margin-bottom: 5px;
+      }
+      .ant-form-item-control {
+        line-height: 24px;
+      }
+      .ant-form-item-label {
+        line-height: 25px;
+      }
+      .ant-form-item-children {
+        line-height: 22px;
+      }
+      .ant-col-sm-8 {
+        width: 10.5%;
+      }
+      .ant-col-sm-16 {
+        width: 89.5%;
+      }
+    }
+    .add {
+      padding-top: 4px;
+    }
+  }
+  .custom-table .ant-empty {
+    margin: 20px 8px!important;
+  }
+  .errorval {
+    display: inline-block;
+    width: 30px;
+  }
+  .operation-btn {
+    display: inline-block;
+    font-size: 16px;
+    padding: 0 5px;
+    cursor: pointer;
+  }
+}
\ No newline at end of file
diff --git a/src/templates/sharecomponent/actioncomponent/verifyprint/editable/index.jsx b/src/templates/sharecomponent/actioncomponent/verifyprint/editable/index.jsx
new file mode 100644
index 0000000..e328414
--- /dev/null
+++ b/src/templates/sharecomponent/actioncomponent/verifyprint/editable/index.jsx
@@ -0,0 +1,241 @@
+import React, {Component} from 'react'
+import { Table, Input, Button, Popconfirm, Form, Icon } from 'antd'
+import Utils from '@/utils/utils.js'
+import './index.scss'
+
+const EditableContext = React.createContext()
+
+const EditableRow = ({ form, index, ...props }) => (
+  <EditableContext.Provider value={form}>
+    <tr {...props} />
+  </EditableContext.Provider>
+)
+
+const EditableFormRow = Form.create()(EditableRow)
+
+class EditableCell extends Component {
+  state = {
+    editing: false
+  }
+
+  toggleEdit = () => {
+    const editing = !this.state.editing
+    this.setState({ editing }, () => {
+      if (editing && this.input && this.input.select) {
+        this.input.select()
+      } else if (editing && this.input && this.input.focus) {
+        this.input.focus()
+      }
+    })
+  }
+
+  save = e => {
+    const { record, handleSave } = this.props
+    this.form.validateFields((error, values) => {
+      handleSave({ ...record, ...values })
+      if (error && error[e.currentTarget.id]) {
+        return
+      }
+      this.toggleEdit()
+    })
+  }
+
+  renderCell = form => {
+    this.form = form
+    const { children, dataIndex, record } = this.props
+    const { editing } = this.state
+
+    return editing ? (
+      <Form.Item style={{ margin: 0 }}>
+        {form.getFieldDecorator(dataIndex, {
+          rules: [
+            {
+              required: true,
+              message: 'NOT NULL.',
+            },
+          ],
+          initialValue: record[dataIndex]
+        })(<Input ref={node => (this.input = node)} autoComplete="off" onPressEnter={this.save} onBlur={this.save} />)}
+      </Form.Item>
+    ) : (
+      <div
+        className="editable-cell-value-wrap"
+        onClick={this.toggleEdit}
+      >
+        {children}
+      </div>
+    )
+  }
+
+  render() {
+    const {
+      editable,
+      dataIndex,
+      title,
+      record,
+      index,
+      handleSave,
+      children,
+      ...restProps
+    } = this.props
+    return (
+      <td {...restProps}>
+        {editable ? (
+          <EditableContext.Consumer style={{padding: 0}}>{this.renderCell}</EditableContext.Consumer>
+        ) : (
+          children
+        )}
+      </td>
+    )
+  }
+}
+
+class EditTable extends Component {
+  constructor(props) {
+    super(props)
+
+    let columns = [
+      {
+        title: 'Value',
+        dataIndex: 'Value',
+        width: '40%',
+        editable: true
+      },
+      {
+        title: 'Text',
+        dataIndex: 'Text',
+        width: '40%',
+        editable: true
+      },
+      {
+        title: '鎿嶄綔',
+        align: 'center',
+        dataIndex: 'operation',
+        render: (text, record) =>
+          this.state.dataSource.length >= 1 ? (
+            <div>
+              <span className="operation-btn" title={props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
+              <span className="operation-btn" title={props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
+              <Popconfirm
+                title={props.dict['header.form.query.delete']}
+                okText={props.dict['model.confirm']}
+                cancelText={props.dict['header.cancel']}
+                onConfirm={() => this.handleDelete(record.key)
+              }>
+                <span style={{color: '#1890ff', cursor: 'pointer'}}><Icon type="delete" /></span>
+              </Popconfirm>
+            </div>
+          ) : null,
+      }
+    ]
+
+    this.state = {
+      columns: columns,
+      dataSource: props.data,
+      count: props.data.length,
+      linkSubFields: props.linkSubFields
+    }
+  }
+
+  handleUpDown = (record, direction) => {
+    const { dataSource } = this.state
+    let index = 0
+
+    let _data = dataSource.filter((item, i) => {
+      if (item.key === record.key) {
+        index = i
+      }
+
+      return item.key !== record.key
+    })
+    if ((index === 0 && direction === 'up') || (index === dataSource.length - 1 && direction === 'down')) {
+      return
+    }
+
+    if (direction === 'up') {
+      _data.splice(index - 1, 0, record)
+    } else {
+      _data.splice(index + 1, 0, record)
+    }
+
+    this.setState({
+      dataSource: _data
+    })
+  }
+
+  handleDelete = key => {
+    const dataSource = [...this.state.dataSource]
+    this.setState({ dataSource: dataSource.filter(item => item.key !== key) })
+  }
+
+  handleAdd = () => {
+    const { count, dataSource } = this.state
+    const newData = {
+      key: Utils.getuuid(),
+      Value: `${count}`,
+      Text: `${count}`
+    }
+
+    this.setState({
+      dataSource: [...dataSource, newData],
+      count: count + 1
+    })
+  }
+
+  handleSave = row => {
+    const newData = [...this.state.dataSource]
+    const index = newData.findIndex(item => row.key === item.key)
+    const item = newData[index]
+    newData.splice(index, 1, {
+      ...item,
+      ...row
+    })
+    this.setState({ dataSource: newData })
+  }
+
+  UNSAFE_componentWillReceiveProps () {
+    
+  }
+
+  render() {
+    const { dataSource } = this.state
+    const components = {
+      body: {
+        row: EditableFormRow,
+        cell: EditableCell
+      }
+    }
+    const columns = this.state.columns.map(col => {
+      if (!col.editable) {
+        return col
+      }
+      return {
+        ...col,
+        onCell: record => ({
+          record,
+          editable: col.editable,
+          dataIndex: col.dataIndex,
+          title: col.title,
+          handleSave: this.handleSave,
+        })
+      }
+    })
+    return (
+      <div className="print-verify-edit-table">
+        <Button onClick={this.handleAdd} className="add-row mk-green">
+          娣诲姞
+        </Button>
+        <Table
+          components={components}
+          rowClassName={() => 'editable-row'}
+          bordered
+          dataSource={dataSource}
+          columns={columns}
+          pagination={false}
+        />
+      </div>
+    )
+  }
+}
+
+export default EditTable
\ No newline at end of file
diff --git a/src/templates/sharecomponent/actioncomponent/verifyprint/editable/index.scss b/src/templates/sharecomponent/actioncomponent/verifyprint/editable/index.scss
new file mode 100644
index 0000000..8b237cd
--- /dev/null
+++ b/src/templates/sharecomponent/actioncomponent/verifyprint/editable/index.scss
@@ -0,0 +1,48 @@
+.print-verify-edit-table {
+  margin: 10px 20px;
+  .add-row {
+    position: absolute;
+    z-index: 1;
+    right: 32px;
+    top: -40px;
+  }
+  .ant-table-thead > tr > th {
+    padding: 10px 16px;
+  }
+  .ant-table-tbody > tr > td {
+    padding: 0px 16px;
+  }
+  .editable-cell-value-wrap {
+    cursor: pointer;
+    height: 40px;
+    width: 500px;
+    display: table-cell;
+    vertical-align: middle;
+    word-wrap: break-word;
+    word-break: break-word;
+    .ant-input {
+      height: 30px;
+      padding: 0 11px;
+    }
+  }
+  .ant-form-item-control-wrapper {
+    width: 100%;
+  }
+  .ant-table-placeholder {
+    padding: 5px 16px;
+    .ant-empty-normal {
+      margin: 0;
+    }
+  }
+  .operation-btn {
+    margin-right: 10px;
+    cursor: pointer;
+  }
+  .ant-table-content {
+    .ant-table-placeholder {
+      .ant-empty.ant-empty-normal {
+        margin: 50px 8px;
+      }
+    }
+  }
+}
diff --git a/src/templates/sharecomponent/actioncomponent/verifyprint/index.jsx b/src/templates/sharecomponent/actioncomponent/verifyprint/index.jsx
new file mode 100644
index 0000000..452d7ed
--- /dev/null
+++ b/src/templates/sharecomponent/actioncomponent/verifyprint/index.jsx
@@ -0,0 +1,461 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Tabs, Row, Col, Button, notification, Modal, message, InputNumber, Input, Select, Radio } from 'antd'
+import moment from 'moment'
+import {UnControlled as CodeMirror} from 'react-codemirror2'
+import 'codemirror/mode/javascript/javascript'
+
+import Api from '@/api'
+import Utils from '@/utils/utils.js'
+import EditTable from './editable'
+
+import 'codemirror/lib/codemirror.css'
+// import 'codemirror/theme/solarized.css'
+import 'codemirror/theme/cobalt.css'
+
+import './index.scss'
+
+const { TabPane } = Tabs
+let _printFunc = null // antd 鏃犳硶鑾峰彇 codemirror 鍐呭锛屾墜鍔ㄦ帶鍒�
+
+class VerifyCard extends Component {
+  static propTpyes = {
+    floor: PropTypes.any,      // 鏄惁涓哄瓙琛�
+    btnTab: PropTypes.any,     // 琛ㄥ崟鏍囩椤碉紙鎸夐挳锛夊弬鏁�
+    config: PropTypes.any,     // 琛ㄥ崟鏍囩椤靛弬鏁�
+    dict: PropTypes.object,    // 瀛楀吀椤�
+    card: PropTypes.object,
+    columns: PropTypes.array
+  }
+
+  state = {
+    verify: {},
+    templates: [],
+    selectimg: '',
+    printMode: 'normal'
+  }
+
+  UNSAFE_componentWillMount() {
+    let _verify = this.props.card.verify || {}
+
+    _verify.Template = _verify.Template || ''
+    _verify.printerTypeList = _verify.printerTypeList || []
+    _verify.linkType = _verify.linkType || 'system'
+    _verify.printMode = _verify.printMode || 'normal'
+
+    this.setState({
+      verify: _verify,
+      linkType: _verify.linkType,
+      printMode: _verify.printMode,
+      printFunc: _verify.printFunc || '// Function(data, form, printer, notification) data-鎵撳嵃鏁版嵁鍒楄〃锛宖orm-琛ㄥ崟淇℃伅锛堜笉瀛樺湪鏃朵负{}锛夛紝printer-鎵撳嵃璁剧疆锛宯otification-淇℃伅鎻愮ず鎺т欢'
+    })
+
+    _printFunc = _verify.printFunc || ''
+  }
+
+  componentDidMount() {
+    let _sql = `select PrintTempNO,Images,PrintTempNO+PrintTempName as PN from sPrintTemplate 
+    where appkey= @appkey@ and Deleted=0 
+    union select ID,Images,a.PrintTempNO+PrintTempName as PN 
+    from (select * from sPrintTemplate where appkey= '' and Deleted=0 ) a 
+    left join (select PrintTempNO from sPrintTemplate where appkey= @appkey@ and Deleted=0 ) b 
+    on a.PrintTempNO=b.PrintTempNO 
+    left join (select Srcid from sPrintTemplate_Log where appkey='' and apicode= @appkey@ and Deleted=0 ) c 
+    on a.ID=c.Srcid where b.PrintTempNO is null and c.Srcid is null`
+
+    let param = {
+      func: 'sPC_Get_SelectedList',
+      LText: Utils.formatOptions(_sql),
+      obj_name: 'data',
+      arr_field: 'PN,PrintTempNO,Images'
+    }
+
+    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
+    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
+
+    Api.getSystemConfig(param).then(res => {
+      if (res.status) {
+        let temps = res.data.map(temp => {
+          return {
+            value: temp.PrintTempNO,
+            text: temp.PN,
+            img: temp.Images
+          }
+        })
+
+        let Template = this.state.verify.Template
+        let selectimg = ''
+        let selectTemp = temps.filter(temp => temp.value === Template)[0]
+
+        if (!selectTemp) {
+          Template = ''
+        } else {
+          selectimg = selectTemp.img
+        }
+
+        this.setState({
+          selectimg: selectimg,
+          templates: temps,
+          verify: {
+            ...this.state.verify,
+            Template: Template
+          }
+        })
+      } else {
+        notification.warning({
+          top: 92,
+          message: res.message,
+          duration: 5
+        })
+      }
+    })
+  }
+
+  showError = (errorType) => {
+    if (errorType === 'S') {
+      notification.success({
+        top: 92,
+        message: '鎵ц鎴愬姛锛�',
+        duration: 2
+      })
+    } else if (errorType === 'Y') {
+      Modal.success({
+        title: '鎵ц鎴愬姛锛�'
+      })
+    } else if (errorType === 'F') {
+      notification.error({
+        className: 'notification-custom-error',
+        top: 92,
+        message: '鎵ц澶辫触锛�',
+        duration: 10
+      })
+    } else if (errorType === 'N') {
+      notification.error({
+        top: 92,
+        message: '鎵ц澶辫触锛�',
+        duration: 10
+      })
+    } else if (errorType === 'E') {
+      Modal.error({
+        title: '鎵ц澶辫触锛�'
+      })
+    } else if (errorType === 'NM') {
+      message.error('鎵ц澶辫触锛�')
+    }
+  }
+
+  timeChange = (val, type) => {
+    const { verify } = this.state
+
+    this.setState({
+      verify: {...verify, [type]: val}
+    })
+  }
+
+  changeTemplate = (val) => {
+    const { templates } = this.state
+
+    let temp = templates.filter(temp => temp.value === val)[0]
+
+    this.setState({
+      selectimg: temp.img
+    })
+  }
+
+  handleConfirm = () => {
+    const { verify } = this.state
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          let _verify = {...verify, ...values, printFunc: _printFunc}
+
+          if (this.refs.editTable && this.refs.editTable.state) {
+            let printTypes = this.refs.editTable.state.dataSource
+  
+            let emptys = printTypes.filter(item => !item.Value || !item.Text)
+            let valMap = new Map()
+            let isvalid = true
+  
+            printTypes.forEach(item => {
+              if (valMap.has(item.Value)) {
+                isvalid = false
+              } else {
+                valMap.set(item.Value, item.Text)
+              }
+            })
+  
+            if (emptys.length > 0) {
+              notification.warning({
+                top: 92,
+                message: '鎵撳嵃绫诲瀷琛ㄦ牸涓璙alue銆乀ext瀛楁涓嶅彲涓虹┖!',
+                duration: 5
+              })
+              return
+            } else if (!isvalid) {
+              notification.warning({
+                top: 92,
+                message: '鎵撳嵃绫诲瀷琛ㄦ牸涓璙alue瀛楁涓嶅彲閲嶅!',
+                duration: 5
+              })
+              return
+            }
+  
+            _verify.printerTypeList = printTypes
+          }
+
+          resolve(_verify)
+        } else {
+          notification.warning({
+            top: 92,
+            message: '閾炬帴鍦板潃涓庢墦鍗版ā鏉夸笉鍙负绌�!',
+            duration: 5
+          })
+        }
+      })
+    })
+  }
+
+  changePrintMode = (e) => {
+    let value = e.target.value
+
+    this.setState({
+      printMode: value
+    })
+  }
+
+  changeLinkType = (e) => {
+    let value = e.target.value
+
+    this.setState({
+      linkType: value
+    }, () => {
+      if (value === 'system') {
+        this.props.form.setFieldsValue({
+          linkUrl: '127.0.0.1:13529'
+        })
+      }
+    })
+  }
+
+  render() {
+    const { getFieldDecorator } = this.props.form
+
+    const { verify, linkType, printMode, printFunc } = this.state
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <div id="verify-card-box-tab">
+        <Tabs defaultActiveKey="1" className="verify-card-print-box" onChange={this.tabchange}>
+          <TabPane tab="鎵撳嵃楠岃瘉" key="1">
+            <Form {...formItemLayout}>
+              <Row gutter={24}>
+                <Col span={8}>
+                  <Form.Item label={'鎵撳嵃妯″紡'}>
+                    {getFieldDecorator('printMode', {
+                      initialValue: printMode || 'normal'
+                    })(
+                      <Radio.Group onChange={this.changePrintMode}>
+                        <Radio value="normal">鏍囧噯</Radio>
+                        <Radio value="custom">鑷畾涔�</Radio>
+                      </Radio.Group>
+                    )}
+                  </Form.Item>
+                </Col>
+                <Col span={8}>
+                  <Form.Item label={'閾炬帴绫诲瀷'}>
+                    {getFieldDecorator('linkType', {
+                      initialValue: linkType || 'system'
+                    })(
+                      <Radio.Group onChange={this.changeLinkType}>
+                        <Radio value="system">绯荤粺</Radio>
+                        <Radio value="custom">鑷畾涔�</Radio>
+                      </Radio.Group>
+                    )}
+                  </Form.Item>
+                </Col>
+                <Col span={8}>
+                  <Form.Item label={'閾炬帴鍦板潃'}>
+                    {getFieldDecorator('linkUrl', {
+                      initialValue: verify.linkUrl || '127.0.0.1:13529',
+                      rules: [
+                        {
+                          required: true,
+                          message: this.props.dict['form.required.input'] + '閾炬帴鍦板潃!'
+                        }
+                      ]
+                    })(<Input placeholder="" autoComplete="off" disabled={linkType === 'system'} />)}
+                  </Form.Item>
+                </Col>
+                {printMode === 'custom' ? <Col span={24}>
+                  <Form.Item label={'澶勭悊鍑芥暟'} className="printFunc">
+                    {getFieldDecorator('printFunc', {
+                      initialValue: printFunc || '',
+                      rules: [
+                        {
+                          required: true,
+                          message: this.props.dict['form.required.input'] + '澶勭悊鍑芥暟!'
+                        }
+                      ]
+                    })(
+                      <CodeMirror
+                        className="code-mirror-area"
+                        options={{
+                          mode: 'text/javascript',
+                          theme: 'cobalt',
+                          lineNumbers: true,
+                          lineWrapping: true
+                        }}
+                        onBeforeChange={() => {}}
+                        onBlur={(editor) => {
+                          _printFunc = editor.getValue()
+                        }}
+                      />
+                    )} 
+                  </Form.Item>
+                </Col> : null}
+                {printMode === 'normal' ? <Col span={8}>
+                  <Form.Item label={'鎵撳嵃妯℃澘'}>
+                    {getFieldDecorator('Template', {
+                      initialValue: verify.Template || '',
+                      rules: [
+                        {
+                          required: true,
+                          message: this.props.dict['form.required.select'] + '鎵撳嵃妯℃澘!'
+                        }
+                      ]
+                    })(
+                      <Select onChange={this.changeTemplate}>
+                        {this.state.templates.map((option, key) =>
+                          <Select.Option id={key} key={key} value={option.value}>
+                            {option.text}
+                          </Select.Option>
+                        )}
+                      </Select>
+                    )}
+                  </Form.Item>
+                </Col> : null }
+                {printMode === 'normal' ? <Col span={8} offset={8}>
+                  <img className="legend" src={this.state.selectimg} alt=""/>
+                </Col> : null }
+              </Row>
+            </Form>
+          </TabPane>
+          <TabPane tab="鎵撳嵃绫诲瀷" key="2">
+            <Form {...formItemLayout}>
+              <Row gutter={24}>
+                <Col span={24} className="print-tip">
+                  <Form.Item label={'鎻愮ず'}>
+                    濡傛灉姝ゆ寜閽殑鎵撳嵃鍔熻兘娑夊強澶氱鎵撳嵃绫诲瀷锛屼笖涓嶅悓绫诲瀷闇�瑕佽缃笉鍚岀殑鎵撳嵃鏈烘椂锛屽彲浠ユ坊鍔犳墦鍗扮被鍨嬫帶鍒朵俊鎭紝
+                    璁剧疆瀹屾垚鍚庯紝鐢ㄦ埛鍙拡瀵逛笉鍚岀殑绫诲瀷璁剧疆瀵瑰簲鐨勬墦鍗版満銆傛敞锛氬湪杩斿洖鏁版嵁椤跺眰缁撴瀯涓坊鍔� printType銆乸rintCount銆乼emplateID 瀛楁锛屽彲鍒嗗埆鎺у埗鎵撳嵃绫诲瀷銆佹墦鍗版暟閲忓拰鎵撳嵃妯℃澘銆�
+                  </Form.Item>
+                </Col>
+                <Col span={24}>
+                  <EditTable data={verify.printerTypeList} dict={this.props.dict} ref="editTable"/>
+                </Col>
+              </Row>
+            </Form>
+          </TabPane>
+          <TabPane tab="淇℃伅鎻愮ず" key="7">
+            <Form {...formItemLayout}>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> S </span>
+                    <Button onClick={() => {this.showError('S')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+                <Col span={8}>
+                  <Form.Item label={'鍋滅暀鏃堕棿'}>
+                    <InputNumber defaultValue={verify.stime || 2} min={1} max={10000} precision={0} onChange={(val) => {this.timeChange(val, 'stime')}} />
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> Y </span>
+                    <Button onClick={() => {this.showError('Y')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> N </span>
+                    <Button onClick={() => {this.showError('N')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+                <Col span={8}>
+                  <Form.Item label={'鍋滅暀鏃堕棿'}>
+                    <InputNumber defaultValue={verify.ntime || 10} min={1} max={10000} precision={0} onChange={(val) => {this.timeChange(val, 'ntime')}} />
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> F </span>
+                    <Button onClick={() => {this.showError('F')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+                <Col span={8}>
+                  <Form.Item label={'鍋滅暀鏃堕棿'}>
+                    <InputNumber defaultValue={verify.ftime || 10} min={1} max={10000} precision={0} onChange={(val) => {this.timeChange(val, 'ftime')}} />
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> E </span>
+                    <Button onClick={() => {this.showError('E')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> NM </span>
+                    <Button onClick={() => {this.showError('NM')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label={'鎻愮ず缂栫爜'}>
+                    <span className="errorval"> -1 </span>
+                    涓嶆彁绀�
+                  </Form.Item>
+                </Col>
+              </Row>
+            </Form>
+          </TabPane>
+        </Tabs>
+      </div>
+    )
+  }
+}
+
+export default Form.create()(VerifyCard)
\ No newline at end of file
diff --git a/src/templates/sharecomponent/actioncomponent/verifyprint/index.scss b/src/templates/sharecomponent/actioncomponent/verifyprint/index.scss
new file mode 100644
index 0000000..6b181b0
--- /dev/null
+++ b/src/templates/sharecomponent/actioncomponent/verifyprint/index.scss
@@ -0,0 +1,60 @@
+.verify-card-print-box {
+  .ant-tabs-nav-scroll {
+    text-align: center;
+  }
+  .ant-tabs-content {
+    min-height: 40vh;
+    .ant-form-item {
+      margin-bottom: 10px;
+    }
+  }
+  .ant-input-disabled {
+    color: rgba(0, 0, 0, 0.65);
+    cursor: default;
+  }
+  .errorval {
+    display: inline-block;
+    width: 30px;
+  }
+  .operation-btn {
+    display: inline-block;
+    font-size: 16px;
+    padding: 0 5px;
+    cursor: pointer;
+  }
+  .legend {
+    width: 100%;
+    margin-bottom: 25px;
+    margin-left: -2px;
+    box-shadow: 0px 0px 2px #bcbcbc;
+  }
+  .printFunc {
+    .ant-form-item-label {
+      width: 10.7%;
+    }
+    .ant-form-item-control-wrapper {
+      width: 89.3%;
+    }
+  }
+  .code-mirror-area {
+    font-size : 14px;
+    line-height : 25px;
+
+    .CodeMirror {
+      height: calc(100vh - 360px);
+    }
+  }
+  .print-tip {
+    margin-bottom: 25px;
+    .ant-form-item-label {
+      width: 10.5%;
+      line-height: 25px;
+    }
+    .ant-form-item-control-wrapper {
+      width: 89.5%;
+      .ant-form-item-children {
+        line-height: 25px;
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/templates/sharecomponent/chartgroupcomponent/chartform/index.jsx b/src/templates/sharecomponent/chartgroupcomponent/chartform/index.jsx
new file mode 100644
index 0000000..0d0c26d
--- /dev/null
+++ b/src/templates/sharecomponent/chartgroupcomponent/chartform/index.jsx
@@ -0,0 +1,379 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Input, Select, InputNumber, Radio, Tooltip, Icon } from 'antd'
+
+import { formRule } from '@/utils/option.js'
+import line1 from '@/assets/img/line1.png'
+import line2 from '@/assets/img/line2.png'
+import line3 from '@/assets/img/line3.png'
+import line4 from '@/assets/img/line4.png'
+import bar1 from '@/assets/img/bar1.png'
+import bar2 from '@/assets/img/bar2.png'
+import bar3 from '@/assets/img/bar3.png'
+import bar4 from '@/assets/img/bar4.png'
+import pie1 from '@/assets/img/pie1.png'
+import pie2 from '@/assets/img/pie2.png'
+import './index.scss'
+
+const syslegends = {
+  line: [
+    {
+      uuid: 'line1',
+      url: line1,
+      options: {
+        shape: 'line',
+        coordinate: 'angle'
+      }
+    },
+    {
+      uuid: 'line2',
+      url: line2,
+      options: {
+        shape: 'smooth',
+        coordinate: 'angle'
+      }
+    },
+    {
+      uuid: 'line3',
+      url: line3,
+      options: {
+        shape: 'hv',
+        coordinate: 'angle'
+      }
+    },
+    {
+      uuid: 'line4',
+      url: line4,
+      options: {
+        shape: 'smooth',
+        coordinate: 'polar'
+      }
+    }
+  ],
+  bar: [
+    {
+      uuid: 'bar1',
+      url: bar1,
+      options: {
+        shape: 'rect',
+        adjust: 'dodge',
+        transpose: 'false'
+      }
+    },
+    {
+      uuid: 'bar2',
+      url: bar2,
+      options: {
+        shape: 'rect',
+        adjust: 'dodge',
+        transpose: 'false'
+      }
+    },
+    {
+      uuid: 'bar3',
+      url: bar3,
+      options: {
+        shape: 'rect',
+        adjust: 'stack',
+        transpose: 'false'
+      }
+    },
+    {
+      uuid: 'bar4',
+      url: bar4,
+      options: {
+        shape: 'rect',
+        adjust: 'dodge',
+        transpose: 'true'
+      }
+    }
+  ],
+  pie: [
+    {
+      uuid: 'pie1',
+      url: pie1,
+      options: {
+        shape: 'pie'
+      }
+    },
+    {
+      uuid: 'pie2',
+      url: pie2,
+      options: {
+        shape: 'ring'
+      }
+    }
+  ]
+}
+
+class ChartForm extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,     // 瀛楀吀椤�
+    MenuID: PropTypes.any,
+    formlist: PropTypes.any,
+    card: PropTypes.any,
+    inputSubmit: PropTypes.any  // 鍥炶溅鎻愪氦浜嬩欢
+  }
+
+  state = {
+    formlist: null,
+    legends: null,
+    selectlegend: null
+  }
+
+  UNSAFE_componentWillMount () {
+    const { card } = this.props
+
+    let _type = card.chartType || 'line'
+    let _legends = null
+    let _selectlegend = null
+
+    if (_type === 'line' || _type === 'bar' || _type === 'line') {
+      _legends = syslegends[_type]
+      _selectlegend = _legends.filter(item => item.uuid === card.modelId)[0]
+
+      if (!_selectlegend) {
+        _selectlegend = _legends[0]
+      }
+    }
+
+    this.setState({
+      legends: _legends,
+      selectlegend: _selectlegend
+    })
+  }
+
+  componentDidMount () {
+    const { card } = this.props
+
+    if (!card.chartType) {
+      try {
+        let _form = document.getElementById('title')
+        _form.select()
+      } catch {
+        console.warn('琛ㄥ崟focus澶辫触锛�')
+      }
+    }
+  }
+
+  handleSubmit = (e) => {
+    e.preventDefault()
+
+    if (this.props.inputSubmit) {
+      this.props.inputSubmit()
+    }
+  }
+
+  typeChange = (key, value) => {
+    if (key === 'chartType') {
+      this.setState({
+        legends: syslegends[value] || null,
+        selectlegend: syslegends[value][0]
+      })
+    }
+  }
+
+  changeSelectLegend = (item) => {
+    this.setState({
+      selectlegend: item
+    })
+  }
+
+  getFields() {
+    const { getFieldDecorator } = this.props.form
+    const fields = []
+    this.props.formlist.forEach((item, index) => {
+      if (item.hidden) return
+      
+      if (item.type === 'text') { // 鏂囨湰鎼滅储
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" overlayClassName={item.tooltipClass} title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || '',
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  },
+                  {
+                    max: formRule.input.max,
+                    message: formRule.input.message
+                  }
+                ]
+              })(<Input placeholder="" autoComplete="off" disabled={item.readonly} onPressEnter={this.handleSubmit} />)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'number') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" overlayClassName={item.tooltipClass} title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  }
+                ]
+              })(<InputNumber min={item.min} max={item.max} precision={item.decimal} />)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'select') { // 涓嬫媺鎼滅储
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || '',
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <Select
+                  showSearch
+                  disabled={!!item.readonly}
+                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                  onChange={(value) => {this.typeChange(item.key, value)}}
+                  getPopupContainer={() => document.getElementById('chartwinter')}
+                >
+                  {item.options.map((option, index) =>
+                    <Select.Option id={`${index}`} title={option.text} key={`${index}`} value={option.value}>
+                      {option.text}
+                    </Select.Option>
+                  )}
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'radio') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <Radio.Group>
+                  {
+                    item.options.map(option => {
+                      return (
+                        <Radio key={option.value} value={option.value}>{option.text}</Radio>
+                      )
+                    })
+                  }
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'multiselect') { // 澶氶��
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || []
+              })(
+                <Select
+                  showSearch
+                  mode="multiple"
+                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                >
+                  {item.options.map((option, i) =>
+                    <Select.Option id={i} key={i} value={option.value}>{option.text}</Select.Option>
+                  )}
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      }
+    })
+    return fields
+  }
+
+  handleConfirm = () => {
+    const { selectlegend } = this.state
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          let result = {...this.props.card, ...values}
+          
+          let icons = {
+            table: 'table',
+            line: 'line-chart',
+            bar: 'bar-chart',
+            pie: 'pie-chart'
+          }
+
+          if (selectlegend && this.props.card.modelId !== selectlegend.uuid) {
+            result = {...result, ...selectlegend.options}
+          }
+
+          if (selectlegend) {
+            result.modelId = selectlegend.uuid
+          }
+
+          if (result.chartType !== 'pie' && result.Yaxis && typeof(result.Yaxis) === 'string') {
+            result.Yaxis = [result.Yaxis]
+          } else if (result.chartType === 'pie' && result.Yaxis && typeof(result.Yaxis) === 'object') {
+            result.Yaxis = result.Yaxis[0] || ''
+          }
+
+          result.icon = icons[result.chartType]
+
+          resolve(result)
+        } else {
+          reject(err)
+        }
+      })
+    })
+  }
+
+  render() {
+    const { legends, selectlegend } = this.state
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 6 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 18 }
+      }
+    }
+    return (
+      <Form {...formItemLayout} className="chart-edit-form" id="chartwinter">
+        <Row gutter={24}>{this.getFields()}</Row>
+        {legends ? <Row gutter={24} className="chart-model-image">
+          {legends.map(item => <Col span={6} key={item.uuid}>
+            <img onClick={() => this.changeSelectLegend(item)} src={item.url} className={selectlegend.uuid === item.uuid ? 'active' : ''} alt=""/>
+          </Col>)}
+        </Row> : null}
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(ChartForm)
\ No newline at end of file
diff --git a/src/templates/sharecomponent/chartgroupcomponent/chartform/index.scss b/src/templates/sharecomponent/chartgroupcomponent/chartform/index.scss
new file mode 100644
index 0000000..a1778ca
--- /dev/null
+++ b/src/templates/sharecomponent/chartgroupcomponent/chartform/index.scss
@@ -0,0 +1,25 @@
+.chart-edit-form {
+  min-height: 190px;
+  .ant-form-item {
+    .ant-input-number {
+      width: 100%;
+    }
+  }
+  .anticon-question-circle {
+    color: #c49f47;
+    position: relative;
+    left: -3px;
+  }
+  .chart-model-image {
+    img {
+      max-width: 100%;
+      cursor: pointer;
+      border: 1px solid #ebedf0;
+      transition: all .3s;
+    }
+    img.active {
+      background-color: rgba(135,59,244,.1);
+      border-color: #873bf4;
+    }
+  }
+}
diff --git a/src/templates/sharecomponent/chartgroupcomponent/dragchartview/card.jsx b/src/templates/sharecomponent/chartgroupcomponent/dragchartview/card.jsx
new file mode 100644
index 0000000..b44ab02
--- /dev/null
+++ b/src/templates/sharecomponent/chartgroupcomponent/dragchartview/card.jsx
@@ -0,0 +1,48 @@
+import React from 'react'
+import { useDrag, useDrop } from 'react-dnd'
+import { Icon } from 'antd'
+import './index.scss'
+
+const Card = ({ id, card, moveCard, findCard, editCard, delCard }) => {
+  const originalIndex = findCard(id).index
+
+  const [{ isDragging }, drag] = useDrag({
+    item: { type: 'chart', id, originalIndex },
+    collect: monitor => ({
+      isDragging: monitor.isDragging(),
+    }),
+  })
+
+  const opacity = isDragging ? 0 : 1
+
+  const edit = () => {
+    editCard(id)
+  }
+  
+  const del = () => {
+    delCard(id)
+  }
+
+  const [, drop] = useDrop({
+    accept: 'chart',
+    canDrop: () => true,
+    hover({ id: draggedId }) {
+      if (!draggedId) return
+      if (draggedId !== id) {
+        const { index: overIndex } = findCard(id)
+        moveCard(draggedId, overIndex)
+      }
+    }
+  })
+
+  return (
+    <div className="chart-tab" style={{ opacity: opacity}}>
+      <div ref={node => drag(drop(node))}>
+        <Icon type={card.icon} />
+      </div>
+      <Icon className="edit" title="缂栬緫" type="edit" onClick={edit} />
+      {card.chartType !== 'table' ? <Icon className="edit close" title="鍒犻櫎" type="close" onClick={del} /> : null}
+    </div>
+  )
+}
+export default Card
diff --git a/src/templates/sharecomponent/chartgroupcomponent/dragchartview/index.jsx b/src/templates/sharecomponent/chartgroupcomponent/dragchartview/index.jsx
new file mode 100644
index 0000000..93d800b
--- /dev/null
+++ b/src/templates/sharecomponent/chartgroupcomponent/dragchartview/index.jsx
@@ -0,0 +1,74 @@
+import React, { useState } from 'react'
+import { useDrop } from 'react-dnd'
+import { is, fromJS } from 'immutable'
+import update from 'immutability-helper'
+import { Tabs } from 'antd'
+import Card from './card'
+import './index.scss'
+
+const { TabPane } = Tabs
+
+const Container = ({activeKey, list, expand, handleList, handleMenu, deleteMenu, changetabview }) => {
+  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(_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 editCard = id => {
+    const { card } = findCard(id)
+    handleMenu(card)
+  }
+
+  const delCard = id => {
+    const { card } = findCard(id)
+    deleteMenu(card)
+  }
+
+  const changetab = id => {
+    if (activeKey === 'all') return
+    
+    changetabview(id)
+  }
+
+  const [, drop] = useDrop({
+    accept: 'chart'
+  })
+
+  return (
+    <div ref={drop} className="ant-row chart-edit-tab-box">
+      <Tabs activeKey={!expand ? activeKey : ''} onChange={changetab}>
+        {cards.map(card => (
+          <TabPane tab={
+            <div key={card.uuid}>
+              <Card
+                key={card.uuid}
+                id={card.uuid}
+                card={card}
+                moveCard={moveCard}
+                editCard={editCard}
+                delCard={delCard}
+                findCard={findCard}
+              />
+            </div>
+          } key={card.uuid}></TabPane>
+        ))}
+      </Tabs>
+    </div>
+  )
+}
+export default Container
diff --git a/src/templates/sharecomponent/chartgroupcomponent/dragchartview/index.scss b/src/templates/sharecomponent/chartgroupcomponent/dragchartview/index.scss
new file mode 100644
index 0000000..91c831e
--- /dev/null
+++ b/src/templates/sharecomponent/chartgroupcomponent/dragchartview/index.scss
@@ -0,0 +1,41 @@
+.chart-edit-tab-box {
+  padding-right: 100px;
+  display: inline-block;
+
+  .ant-tabs-bar {
+    border: 0;
+  }
+  .ant-tabs-tab {
+    margin: 0px;
+    padding: 0px;
+  }
+  .ant-tabs-ink-bar {
+    display: none!important;
+  }
+  .chart-tab {
+    position: relative;
+    width: 40px;
+    padding-top: 15px;
+    text-align: center;
+    display: inline-block;
+    
+    .edit {
+      position: absolute;
+      left: 0;
+      top: 0px;
+      color: #1890ff;
+      cursor: pointer;
+      display: none;
+    }
+    .edit.close {
+      left: 20px;
+      color: #ff4d4f;
+    }
+  }
+
+  .chart-tab:hover {
+    .edit {
+      display: inline-block;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/templates/sharecomponent/chartgroupcomponent/index.jsx b/src/templates/sharecomponent/chartgroupcomponent/index.jsx
new file mode 100644
index 0000000..23be259
--- /dev/null
+++ b/src/templates/sharecomponent/chartgroupcomponent/index.jsx
@@ -0,0 +1,234 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Icon, Modal } from 'antd'
+
+import Utils from '@/utils/utils.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import { getChartViewForm } from '@/templates/zshare/formconfig'
+
+import ChartForm from './chartform'
+import DragChartView from './dragchartview'
+import './index.scss'
+
+const { confirm } = Modal
+
+// **鎮茶鑰呭線寰�姝g‘锛屼箰瑙傝�呭線寰�鎴愬姛
+class ChartGroupComponent extends Component {
+  static propTpyes = {
+    config: PropTypes.object,         // 鑿滃崟閰嶇疆淇℃伅
+    sysRoles: PropTypes.array,        // 瑙掕壊鍒楄〃锛岄粦鍚嶅崟浣跨敤
+    updatechartgroup: PropTypes.func  // 鍥捐〃鏇存柊
+  }
+
+  state = {
+    dict: (!localStorage.getItem('lang') || localStorage.getItem('lang') === 'zh-CN') ? zhCN : enUS,
+    chartlist: null,      // 鍥捐〃闆�
+    card: null,           // 缂栬緫涓厓绱�
+    formlist: null,       // 琛ㄥ崟淇℃伅
+    modaltype: '',        // 妯℃�佹鎺у埗
+    chartview: null       // 娲诲姩鍥捐〃
+  }
+
+  /**
+   * @description 鍥捐〃鍒濆鍖�
+   */
+  UNSAFE_componentWillMount () {
+    this.setState({
+      chartlist: fromJS(this.props.config.charts).toJS(),
+      chartview: this.props.config.charts[0].uuid
+    })
+  }
+
+  /**
+   * @description 鍥捐〃淇℃伅淇敼鏃舵洿鏂� chartlist
+   */
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    const { chartlist } = this.state
+
+    if (nextProps.config && nextProps.config.charts && !is(fromJS(nextProps.config.charts), fromJS(chartlist))) {
+      this.setState({
+        chartlist: fromJS(nextProps.config.charts).toJS()
+      })
+    }
+  }
+
+  /**
+   * @description 鍥捐〃椤哄簭璋冩暣锛屾垨鎷栨嫿娣诲姞
+   */
+  handleList = (list) => {
+    const { config } = this.props
+
+    this.setState({chartlist: list})
+    this.props.updatechartgroup({...config, charts: list}, this.state.chartview)
+  }
+
+  /**
+   * @description 鍙栨秷淇濆瓨锛屽叧闂ā鎬佹
+   */
+  editModalCancel = () => {
+    this.setState({
+      card: null,
+      modaltype: ''
+    })
+  }
+
+  /**
+   * @description 娣诲姞鎴栦慨鏀瑰浘琛�
+   */
+  handleChart = (item) => {
+    let _type = 'editChart'
+    if (!item) {
+      _type = 'addChart'
+      item = {
+        uuid: Utils.getuuid(),
+        label: '',
+        title: '',
+        chartType: 'line',
+        icon: 'line-chart',
+        Hide: 'false',
+        blacklist: []
+      }
+    }
+
+    this.setState({
+      card: item,
+      modaltype: _type,
+      formlist: getChartViewForm(item, this.props.sysRoles)
+    })
+  }
+
+  /**
+   * @description 鍥捐〃淇℃伅淇敼鍚庯紝鎻愪氦淇濆瓨
+   */
+  submitChart = () => {
+    const { config } = this.props
+    const { modaltype } = this.state
+    let _chartlist = fromJS(this.state.chartlist).toJS()
+    let _chartview = this.state.chartview
+
+    this.chartFormRef.handleConfirm().then(res => {
+      if (modaltype === 'addChart') {
+        _chartlist.push(res)
+        _chartview = res.uuid
+      } else {
+        _chartlist = _chartlist.map(item => {
+          if (item.uuid === res.uuid) {
+            if (!is(fromJS(item), fromJS(res))) {
+              let _element = document.getElementById(res.uuid)
+              if (_element) {
+                _element.innerHTML = ''
+              }
+            }
+            return res
+          }
+          return item
+        })
+      }
+
+      this.setState({
+        card: null,
+        chartview: _chartview,
+        modaltype: '',
+        chartlist: _chartlist
+      })
+
+      this.props.updatechartgroup({...config, charts: _chartlist}, _chartview)
+    })
+  }
+
+  /**
+   * @description 鍥捐〃灞曞紑鏀惰捣鍒囨崲
+   */
+  onChartChange = (e) => {
+    const { config } = this.props
+    e.stopPropagation()
+
+    this.props.updatechartgroup({...config, expand: !config.expand}, this.state.chartview)
+  }
+
+  /**
+   * @description 鍥捐〃鍒犻櫎
+   */
+  deletechart = (plot) => {
+    const { config } = this.props
+    const { dict } = this.state
+    let _this = this
+
+    confirm({
+      content: dict['model.confirm'] + dict['model.delete'] + ` ${plot.title} 锛焋,
+      okText: dict['model.confirm'],
+      cancelText: dict['header.cancel'],
+      onOk() {
+        let _chartlist = fromJS(_this.state.chartlist).toJS()
+        let _chartview = this.state.chartview
+
+        _chartlist = _chartlist.filter(item => item.uuid !== plot.uuid)
+
+        if (_chartview === plot.uuid) {
+          _chartview = _chartlist[0].uuid
+        }
+
+        _this.setState({
+          chartlist: _chartlist,
+          chartview: _chartview
+        })
+        _this.props.updatechartgroup({...config, charts: _chartlist}, _chartview)
+      },
+      onCancel() {}
+    })
+  }
+
+  changetabview = (id) => {
+    const { config } = this.props
+
+    this.setState({
+      chartview: id
+    })
+
+    this.props.updatechartgroup(config, id)
+  }
+
+
+  render() {
+    const { config } = this.props
+    const { dict, chartlist, modaltype, card, chartview } = this.state
+
+    return (
+      <div className="model-table-chartview-list">
+        <Icon type="plus" onClick={() => this.handleChart()} />
+        {chartlist.length > 1 ? <Icon type={config.expand ? 'up' : 'down'} onClick={this.onChartChange} /> : null}
+        {chartlist.length > 1 ? <DragChartView
+          activeKey={chartview}
+          list={chartlist}
+          expand={config.expand}
+          handleList={this.handleList}
+          changetabview={this.changetabview}
+          handleMenu={this.handleChart}
+          deleteMenu={this.deletechart}
+        /> : null}
+        {/* 鍚堝苟鍒楃紪杈� */}
+        <Modal
+          title={modaltype === 'addChart' ? '鍥捐〃-娣诲姞' : '鍥炬爣-缂栬緫'}
+          visible={modaltype === 'addChart' || modaltype === 'editChart'}
+          width={750}
+          maskClosable={false}
+          onOk={this.submitChart}
+          onCancel={this.editModalCancel}
+          destroyOnClose
+        >
+          <ChartForm
+            dict={dict}
+            card={card}
+            formlist={this.state.formlist}
+            inputSubmit={this.submitChart}
+            wrappedComponentRef={(inst) => this.chartFormRef = inst}
+          />
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default ChartGroupComponent
\ No newline at end of file
diff --git a/src/templates/sharecomponent/chartgroupcomponent/index.scss b/src/templates/sharecomponent/chartgroupcomponent/index.scss
new file mode 100644
index 0000000..e12939a
--- /dev/null
+++ b/src/templates/sharecomponent/chartgroupcomponent/index.scss
@@ -0,0 +1,24 @@
+.model-table-chartview-list {
+  position: absolute;
+  right: 0;
+  top: -10px;
+  text-align: right;
+  z-index: 10;
+  > .anticon-plus {
+    position: absolute;
+    right: 17px;
+    z-index: 11;
+    color: #26C281;
+    cursor: pointer;
+    font-size: 18px;
+    margin-top: 15px;
+  }
+  .anticon-down, .anticon-up {
+    position: absolute;
+    right: 55px;
+    z-index: 11;
+    cursor: pointer;
+    font-size: 16px;
+    margin-top: 18px;
+  }
+}
\ No newline at end of file
diff --git a/src/templates/sharecomponent/chartgroupcomponent/searcheditable/index.jsx b/src/templates/sharecomponent/chartgroupcomponent/searcheditable/index.jsx
new file mode 100644
index 0000000..8abe02b
--- /dev/null
+++ b/src/templates/sharecomponent/chartgroupcomponent/searcheditable/index.jsx
@@ -0,0 +1,265 @@
+import React, {Component} from 'react'
+import { is, fromJS } from 'immutable'
+import { Table, Input, Button, Popconfirm, Form, Icon } from 'antd'
+import Utils from '@/utils/utils.js'
+import './index.scss'
+
+const EditableContext = React.createContext()
+
+const EditableRow = ({ form, index, ...props }) => (
+  <EditableContext.Provider value={form}>
+    <tr {...props} />
+  </EditableContext.Provider>
+)
+
+const EditableFormRow = Form.create()(EditableRow)
+
+class EditableCell extends Component {
+  state = {
+    editing: false
+  }
+
+  toggleEdit = () => {
+    const editing = !this.state.editing
+    this.setState({ editing }, () => {
+      if (editing && this.input && this.input.select) {
+        this.input.select()
+      } else if (editing && this.input && this.input.focus) {
+        this.input.focus()
+      }
+    })
+  }
+
+  save = e => {
+    const { record, handleSave } = this.props
+    this.form.validateFields((error, values) => {
+      handleSave({ ...record, ...values })
+      if (error && error[e.currentTarget.id]) {
+        return
+      }
+      this.toggleEdit()
+    })
+  }
+
+  renderCell = form => {
+    this.form = form
+    const { children, dataIndex, record } = this.props
+    const { editing } = this.state
+    return editing ? (
+      <Form.Item style={{ margin: 0 }}>
+        {form.getFieldDecorator(dataIndex, {
+          rules: [
+            {
+              required: true,
+              message: 'NOT NULL.',
+            },
+          ],
+          initialValue: record[dataIndex]
+        })(<Input ref={node => (this.input = node)} autoComplete="off" onPressEnter={this.save} onBlur={this.save} />)}
+      </Form.Item>
+    ) : (
+      <div
+        className="editable-cell-value-wrap"
+        onClick={this.toggleEdit}
+      >
+        {children}
+      </div>
+    )
+  }
+
+  render() {
+    const {
+      editable,
+      dataIndex,
+      title,
+      record,
+      index,
+      handleSave,
+      children,
+      ...restProps
+    } = this.props
+    return (
+      <td {...restProps}>
+        {editable ? (
+          <EditableContext.Consumer style={{padding: 0}}>{this.renderCell}</EditableContext.Consumer>
+        ) : (
+          children
+        )}
+      </td>
+    )
+  }
+}
+
+class EditTable extends Component {
+  constructor(props) {
+    super(props)
+    let columns = [
+      {
+        title: 'Value',
+        dataIndex: 'Value',
+        width: props.type === 'link' ? '27%' : '40%',
+        editable: true
+      },
+      {
+        title: 'Text',
+        dataIndex: 'Text',
+        width: props.type === 'link' ? '27%' : '40%',
+        editable: true
+      },
+      {
+        title: 'Action',
+        align: 'center',
+        dataIndex: 'operation',
+        render: (text, record) =>
+          this.state.dataSource.length >= 1 ? (
+            <Popconfirm title="Sure to delete?" onConfirm={() => this.handleDelete(record.key)}>
+              <span style={{color: '#1890ff', cursor: 'pointer'}}><Icon type="delete" /></span>
+            </Popconfirm>
+          ) : null,
+      }
+    ]
+
+    if (props.type === 'link') {
+      columns.unshift({
+        title: 'ParentID',
+        dataIndex: 'ParentID',
+        width: '27%',
+        editable: true
+      })
+    }
+
+    this.state = {
+      columns: columns,
+      dataSource: props.data,
+      count: props.data.length,
+      type: props.type
+    }
+  }
+
+  handleDelete = key => {
+    const dataSource = [...this.state.dataSource]
+    this.setState({ dataSource: dataSource.filter(item => item.key !== key) })
+  }
+
+  handleAdd = () => {
+    const { type, count, dataSource } = this.state
+    const newData = {
+      key: Utils.getuuid(),
+      Value: `${count}`,
+      Text: `${count}`
+    }
+    if (type === 'link') {
+      newData.ParentID = `${count}`
+    }
+    this.setState({
+      dataSource: [...dataSource, newData],
+      count: count + 1
+    })
+  }
+
+  handleSave = row => {
+    const newData = [...this.state.dataSource]
+    const index = newData.findIndex(item => row.key === item.key)
+    const item = newData[index]
+    newData.splice(index, 1, {
+      ...item,
+      ...row
+    })
+    this.setState({ dataSource: newData })
+  }
+
+  resetColumn = (type) => {
+    let columns = [
+      {
+        title: 'Value',
+        dataIndex: 'Value',
+        width: type === 'link' ? '27%' : '40%',
+        editable: true
+      },
+      {
+        title: 'Text',
+        dataIndex: 'Text',
+        width: type === 'link' ? '27%' : '40%',
+        editable: true
+      },
+      {
+        title: 'Action',
+        align: 'center',
+        dataIndex: 'operation',
+        render: (text, record) =>
+          this.state.dataSource.length >= 1 ? (
+            <Popconfirm title="Sure to delete?" onConfirm={() => this.handleDelete(record.key)}>
+              <span style={{color: '#1890ff', cursor: 'pointer'}}><Icon type="delete" /></span>
+            </Popconfirm>
+          ) : null,
+      }
+    ]
+
+    if (type === 'link') {
+      columns.unshift({
+        title: 'ParentID',
+        dataIndex: 'ParentID',
+        width: '27%',
+        editable: true
+      })
+    }
+
+    this.setState({
+      columns: columns,
+      type: type
+    })
+  }
+
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    if (this.props.type !== nextProps.type) {
+      this.resetColumn(nextProps.type)
+    } else if (!is(fromJS(this.props.data), fromJS(nextProps.data))) {
+      this.setState({
+        dataSource: nextProps.data,
+        count: nextProps.data.length
+      })
+    }
+  }
+
+  render() {
+    const { dataSource } = this.state
+    const components = {
+      body: {
+        row: EditableFormRow,
+        cell: EditableCell
+      }
+    }
+    const columns = this.state.columns.map(col => {
+      if (!col.editable) {
+        return col
+      }
+      return {
+        ...col,
+        onCell: record => ({
+          record,
+          editable: col.editable,
+          dataIndex: col.dataIndex,
+          title: col.title,
+          handleSave: this.handleSave,
+        })
+      }
+    })
+    return (
+      <div className="common-modal-edit-table">
+        <Button onClick={this.handleAdd} type="primary" className="add-row">
+          Add
+        </Button>
+        <Table
+          components={components}
+          rowClassName={() => 'editable-row'}
+          bordered
+          dataSource={dataSource}
+          columns={columns}
+          pagination={false}
+        />
+      </div>
+    )
+  }
+}
+
+export default EditTable
\ No newline at end of file
diff --git a/src/templates/sharecomponent/chartgroupcomponent/searcheditable/index.scss b/src/templates/sharecomponent/chartgroupcomponent/searcheditable/index.scss
new file mode 100644
index 0000000..f8f0942
--- /dev/null
+++ b/src/templates/sharecomponent/chartgroupcomponent/searcheditable/index.scss
@@ -0,0 +1,36 @@
+.common-modal-edit-table {
+  .add-row {
+    position: absolute;
+    z-index: 1;
+    right: 12px;
+    top: -40px;
+  }
+  .ant-table-thead > tr > th {
+    padding: 10px 16px;
+  }
+  .ant-table-tbody > tr > td {
+    padding: 0px 16px;
+  }
+  .editable-cell-value-wrap {
+    cursor: pointer;
+    height: 40px;
+    width: 100px;
+    display: table-cell;
+    vertical-align: middle;
+    word-wrap: break-word;
+    word-break: break-word;
+    .ant-input {
+      height: 30px;
+      padding: 0 11px;
+    }
+  }
+  .ant-form-item-control-wrapper {
+    width: 100%;
+  }
+  .ant-table-placeholder {
+    padding: 5px 16px;
+    .ant-empty-normal {
+      margin: 0;
+    }
+  }
+}
diff --git a/src/templates/sharecomponent/chartgroupcomponent/searchform/index.jsx b/src/templates/sharecomponent/chartgroupcomponent/searchform/index.jsx
new file mode 100644
index 0000000..e7941ec
--- /dev/null
+++ b/src/templates/sharecomponent/chartgroupcomponent/searchform/index.jsx
@@ -0,0 +1,475 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Input, Select, Icon, Radio, notification, Tooltip, InputNumber } from 'antd'
+import { dateOptions, matchReg, formRule } from '@/utils/option.js'
+import EditTable from '../searcheditable'
+import Utils from '@/utils/utils.js'
+import './index.scss'
+
+const { TextArea } = Input
+
+class MainSearch extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,     // 瀛楀吀椤�
+    formlist: PropTypes.any,    // 琛ㄥ崟
+    optionLibs: PropTypes.any,  // 鑷畾涔変笅鎷夐泦
+    card: PropTypes.object,     // 鎼滅储鏉′欢淇℃伅
+    inputSubmit: PropTypes.any  // 鍥炶溅鎻愪氦浜嬩欢
+  }
+
+  state = {
+    openType: null,          // 鎼滅储鏉′欢鏄剧ず绫诲瀷
+    resourceType: null,      // 涓嬫媺鎼滅储鏃讹紝閫夐」鏉ユ簮绫诲瀷
+    formlist: null           // 琛ㄥ崟
+  }
+
+  /**
+   * @description 琛ㄥ崟棰勫鐞�
+   * 1銆佹牴鎹〃鍗曠被鍨嬶紝鏄剧ず琛ㄥ崟鍙紪杈戦」
+   * 2銆佷笅鎷夐�夋嫨锛屾牴鎹暟鎹簮绫诲瀷鏄剧ず鐩稿叧閰嶇疆
+   */
+  UNSAFE_componentWillMount () {
+    const { formlist, optionLibs } = this.props
+
+    let type = formlist.filter(cell => cell.key === 'type')[0].initVal
+    let resourceType = formlist.filter(cell => cell.key === 'resourceType')[0].initVal
+    let _options = ['label', 'field', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required']                // 榛樿鏄剧ず椤�
+
+    if ((type === 'multiselect' || type === 'select' || type === 'link') && resourceType === '0') {        // 涓嬫媺閫夋嫨绫诲瀷銆侀�夐」涓鸿嚜瀹氫箟璧勬簮
+      _options = [..._options, 'resourceType', 'options', 'display', 'quick']
+    } else if ((type === 'multiselect' || type === 'select' || type === 'link') && resourceType === '1') { // 涓嬫媺閫夋嫨绫诲瀷銆侀�夐」涓哄悗鍙版暟鎹簮涓幏鍙�
+      _options = [..._options, 'resourceType', 'dataSource', 'valueField', 'valueText', 'orderBy', 'orderType', 'display', 'database']
+    }
+
+    if (type === 'select' || type === 'link') {
+      _options.push('setAll')
+    }
+
+    if (type === 'link') { // 鍏宠仈绫诲瀷銆佸鍔犲叧鑱斾笂绾х殑瀛楁鍚�
+      _options = [..._options, 'linkField']
+    }
+    
+    this.setState({
+      openType: type,
+      resourceType: resourceType,
+      formlist: formlist.map(form => {
+        // 琛ㄥ崟涓哄垵濮嬪�煎瓧娈碉紝涓旀暟鎹被鍨嬪睘浜庢椂闂寸被鍨嬫椂锛岃缃垵濮嬪�间负涓嬫媺閫夋嫨锛屽苟閲嶇疆閫夋嫨椤�
+        if (form.key === 'initval' && dateOptions.hasOwnProperty(type)) {
+          form.options = dateOptions[type]
+          form.type = 'select'
+        }
+        // 琛ㄥ崟涓哄尮閰嶅瓧娈垫椂锛屾牴鎹笉鍚岀殑绫诲瀷锛屾樉绀哄搴旂殑鍖归厤瑙勫垯
+        if (form.key === 'match') {
+          if (type === 'text') {
+            form.options = matchReg.text
+          } else if (type === 'multiselect') {
+            form.options = matchReg.multiselect
+          } else if (type === 'select' || type === 'link') {
+            form.options = matchReg.select
+          } else if (type === 'date') {
+            form.options = matchReg.date
+          } else if (type === 'datemonth') {
+            form.options = matchReg.datemonth
+          } else if (type === 'dateweek' || type === 'daterange') {
+            form.options = matchReg.daterange
+          }
+        } else if (form.key === 'quick') {
+          form.options = [...optionLibs.values()].map(cell => {
+            return {
+              value: cell.uuid,
+              text: cell.label + '(' + cell.parname + ')'
+            }
+          })
+        }
+        form.hidden = !_options.includes(form.key)
+        return form
+      })
+    })
+  }
+
+  componentDidMount () {
+    const { card } = this.props
+
+    if (card.focus) {
+      try {
+        let _form = document.getElementById('label')
+        _form.select()
+      } catch {
+        console.warn('琛ㄥ崟focus澶辫触锛�')
+      }
+    }
+  }
+
+  /**
+   * @description 鎼滅储鏉′欢绫诲瀷鍒囨崲
+   */
+  openTypeChange = (key, value) => {
+    const { resourceType } = this.state
+
+    if (key === 'type') {
+      let _options = ['label', 'field', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required']
+
+      if ((value === 'multiselect' || value === 'select' || value === 'link') && resourceType === '0') {        // 涓嬫媺閫夋嫨绫诲瀷銆侀�夐」涓鸿嚜瀹氫箟璧勬簮
+        _options = [..._options, 'resourceType', 'options', 'display', 'quick']
+      } else if ((value === 'multiselect' || value === 'select' || value === 'link') && resourceType === '1') { // 涓嬫媺閫夋嫨绫诲瀷銆侀�夐」涓哄悗鍙版暟鎹簮涓幏鍙�
+        _options = [..._options, 'resourceType', 'dataSource', 'valueField', 'valueText', 'orderBy', 'orderType', 'display', 'database']
+      }
+
+      if (value === 'select' || value === 'link') {
+        _options.push('setAll')
+      }
+      
+      if (value === 'link') {
+        _options = [..._options, 'linkField']
+      }
+
+      this.setState({
+        openType: value,
+        formlist: this.state.formlist.map(form => {
+          form.hidden = !_options.includes(form.key)            // 闅愯棌琛ㄥ崟
+
+          if (form.key === 'initval') {
+            if (dateOptions.hasOwnProperty(value)) { // 鏍规嵁鎼滅储鏉′欢绫诲瀷锛岄�夋嫨鍒濆鍊肩殑绫诲瀷鍙婃暟鎹�
+              form.options = dateOptions[value]
+              form.type = 'select'
+            } else {
+              form.type = 'text'
+            }
+            form.initVal = ''                                    // 鎼滅储鏉′欢绫诲瀷鍒囨崲鏃讹紝鍒濆鍊肩疆绌�
+            form.hidden = true
+          } else if (form.key === 'match') {                     // 鎼滅储鏉′欢绫诲瀷鍒囨崲鏃讹紝鍖归厤瑙勫垯绫诲瀷瀵瑰簲鍒囨崲
+            if (value === 'text') {
+              form.options = matchReg.text
+            } else if (value === 'multiselect') {
+              form.options = matchReg.multiselect
+            } else if (value === 'select' || value === 'link') {
+              form.options = matchReg.select
+            } else if (value === 'date') {
+              form.options = matchReg.date
+            } else if (value === 'datemonth') {
+              form.options = matchReg.datemonth
+            } else if (value === 'dateweek' || value === 'daterange') {
+              form.options = matchReg.daterange
+            }
+            form.hidden = true
+          }
+
+          return form
+        })
+      }, () => {
+        this.setState({
+          formlist: this.state.formlist.map(form => {
+
+            if (form.key === 'initval') {
+              form.hidden = false
+            } else if (form.key === 'match') {
+              form.initVal = form.options[0].value
+              form.hidden = false
+            }
+
+            return form
+          })
+        })
+      })
+    } else if (key === 'quick') {
+      let option = this.props.optionLibs.get(value)
+
+      this.setState({
+        formlist: this.state.formlist.map(form => {
+          if (form.key === 'options') {
+            form.initVal = option.options
+          }
+
+          return form
+        })
+      })
+    }
+  }
+
+  /**
+   * @description 鏁版嵁婧愮被鍨嬪垏鎹�
+   */
+  onChange = (e, key) => {
+    const { openType } = this.state
+    let value = e.target.value
+
+    if (key === 'resourceType') {
+      let _options = ['label', 'field', 'initval', 'type', 'match', 'resourceType', 'display', 'ratio', 'blacklist', 'required']
+
+      if (value === '0') {
+        _options = [..._options, 'options', 'quick']
+      } else if (value === '1') {
+        _options = [..._options, 'dataSource', 'valueField', 'valueText', 'orderBy', 'orderType', 'database']
+      }
+
+      if (openType === 'select' || openType === 'link') {
+        _options.push('setAll')
+      }
+      
+      if (openType === 'link') {
+        _options = [..._options, 'linkField']
+      }
+      
+      this.setState({
+        resourceType: value,
+        formlist: this.state.formlist.map(form => {
+          form.hidden = !_options.includes(form.key)
+          return form
+        })
+      })
+    }
+  }
+
+  handleSubmit = (e) => {
+    e.preventDefault()
+
+    if (this.props.inputSubmit) {
+      this.props.inputSubmit()
+    }
+  }
+
+  getFields() {
+    const { getFieldDecorator } = this.props.form
+    const fields = []
+    this.state.formlist.forEach((item, index) => {
+      if (item.hidden) return
+
+      if (item.type === 'text') { // 鏂囨湰鎼滅储
+        let rules = []
+        if (item.key === 'field') {
+          rules = [{
+            pattern: formRule.field.pattern,
+            message: formRule.field.message
+          }, {
+            max: formRule.field.max,
+            message: formRule.field.maxMessage
+          }]
+        } else {
+          rules = [{
+            max: formRule.input.max,
+            message: formRule.input.message
+          }]
+        }
+        
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" overlayClassName={item.tooltipClass} title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || '',
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  },
+                  ...rules
+                ]
+              })(<Input placeholder="" autoComplete="off" disabled={item.readonly} onPressEnter={this.handleSubmit} />)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'number') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || 6,
+                rules: [
+                  {
+                    required: item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  }
+                ]
+              })(<InputNumber min={item.min} max={item.max} precision={0} />)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'select') { // 涓嬫媺鎼滅储
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || '',
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <Select
+                  showSearch
+                  filterOption={(input, option) => option.props.children[2].toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                  onChange={(value) => {this.openTypeChange(item.key, value)}}
+                  getPopupContainer={() => document.getElementById('commontable-search-form-box')}
+                >
+                  {item.options.map(option =>
+                    <Select.Option id={option.value} title={option.text} key={option.value} value={option.value}>
+                      {item.key === 'icon' && <Icon type={option.text} />} {option.text}
+                    </Select.Option>
+                  )}
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'radio') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <Radio.Group onChange={(e) => {this.onChange(e, item.key)}}>
+                  {
+                    item.options.map(option => {
+                      return (
+                        <Radio key={option.value} value={option.value}>{option.text}</Radio>
+                      )
+                    })
+                  }
+                </Radio.Group>,
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'textarea') {
+        fields.push(
+          <Col span={20} offset={4} key={index}>
+            <Form.Item className="text-area">
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  }
+                ]
+              })(<TextArea rows={4} />)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'options') {
+        fields.push(
+          <Col span={20} offset={4} key={index}>
+            <EditTable data={item.initVal} type={this.state.openType} ref="editTable"/>
+          </Col>
+        )
+      } else if (item.type === 'multiselect') { // 澶氶��
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || []
+              })(
+                <Select
+                  showSearch
+                  mode="multiple"
+                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                >
+                  {item.options.map((option, i) =>
+                    <Select.Option id={i} key={i} value={option.value}>{option.text}</Select.Option>
+                  )}
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      }
+    })
+
+    return fields
+  }
+
+  handleConfirm = () => {
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          let isvalid = true
+          values.uuid = this.props.card.uuid
+          // 涓嬫媺鑿滃崟鎴栧叧鑱旇彍鍗�
+          if ((values.type === 'multiselect' || values.type === 'select' || values.type === 'link') && values.resourceType === '0') {
+            values.options = this.refs.editTable.state.dataSource
+            values.dataSource = ''
+            let emptys = []
+            if (values.type === 'multiselect' || values.type === 'select') {
+              emptys = values.options.filter(op => !(op.Value && op.Text))
+            } else {
+              emptys = values.options.filter(op => !(op.Value && op.Text && op.ParentID))
+            }
+            if (emptys.length > 0) {
+              isvalid = false
+            }
+          } else if ((values.type === 'multiselect' || values.type === 'select' || values.type === 'link') && values.resourceType === '1') {
+            values.options = []
+          }
+
+          if (isvalid) {
+            ['linkField', 'valueField', 'valueText', 'orderBy'].forEach(item => {
+              if (values[item]) {
+                values[item] = values[item].replace(/\s* | \t* | \v* | \r*/ig, '')
+              }
+            })
+
+            let error = Utils.verifySql(values.dataSource)
+
+            if (error) {
+              notification.warning({
+                top: 92,
+                message: '鏁版嵁婧愪腑涓嶅彲浣跨敤' + error,
+                duration: 5
+              })
+              return
+            }
+
+            resolve(values)
+          } else {
+            notification.warning({
+              top: 92,
+              message: this.props.dict['header.form.selectItem.error'],
+              duration: 5
+            })
+          }
+        } else {
+          reject(err)
+        }
+      })
+    })
+  }
+
+  render() {
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+    return (
+      <Form {...formItemLayout} className="ant-advanced-search-form commontable-search-form" id="commontable-search-form-box">
+        <Row gutter={24}>{this.getFields()}</Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(MainSearch)
\ No newline at end of file
diff --git a/src/templates/sharecomponent/chartgroupcomponent/searchform/index.scss b/src/templates/sharecomponent/chartgroupcomponent/searchform/index.scss
new file mode 100644
index 0000000..b027f37
--- /dev/null
+++ b/src/templates/sharecomponent/chartgroupcomponent/searchform/index.scss
@@ -0,0 +1,24 @@
+.ant-advanced-search-form.commontable-search-form {
+  min-height: 180px;
+  .ant-col-offset-4 {
+    padding-left: 6px!important;
+    padding-bottom: 20px;
+  }
+  // .ant-form-item {
+  //   margin-bottom: 10px;
+  // }
+  .ant-form-item.text-area {
+    margin-bottom: 0px;
+    .ant-form-item-control-wrapper {
+      width: 100%;
+    }
+  }
+  .anticon-question-circle {
+    color: #c49f47;
+    position: relative;
+    left: -3px;
+  }
+  .ant-input-number {
+    width: 100%;
+  }
+}
\ No newline at end of file
diff --git a/src/templates/sharecomponent/columncomponent/colspanform/index.jsx b/src/templates/sharecomponent/columncomponent/colspanform/index.jsx
new file mode 100644
index 0000000..670f462
--- /dev/null
+++ b/src/templates/sharecomponent/columncomponent/colspanform/index.jsx
@@ -0,0 +1,193 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Input, InputNumber, Select, Radio } from 'antd'
+import { formRule } from '@/utils/option.js'
+import TransferForm from '@/templates/zshare/transferform'
+import './index.scss'
+
+class MainSearch extends Component {
+  static propTpyes = {
+    dict: PropTypes.object, // 瀛楀吀椤�
+    columns: PropTypes.array,
+    card: PropTypes.any,
+    inputSubmit: PropTypes.any   // 鍥炶溅鎻愪氦浜嬩欢
+  }
+
+  componentDidMount () {
+    try {
+      let _form = document.getElementById('label')
+      if (_form && _form.select) {
+        _form.select()
+      }
+    } catch {
+      console.warn('琛ㄥ崟focus澶辫触锛�')
+    }
+  }
+
+  handleConfirm = () => {
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          let targetKeys = this.refs['column-transfer'].state.targetKeys
+
+          delete values.type // 鍒犻櫎type锛屾澶勫�间负'鍚堝苟鍒�'鏂囧瓧
+
+          let subfield = []  // 鐢ㄤ簬鏌ョ湅鍚堝苟鍒楀瓧娈�
+          this.props.columns.forEach(col => {
+            if (col.field && targetKeys.includes(col.uuid)) {
+              subfield.push(col.field)
+            }
+          })
+          subfield = subfield.join(', ')
+
+          let _card = {...this.props.card, ...values, sublist: targetKeys, subfield: subfield}
+
+          delete _card.focus
+
+          resolve(_card)
+        } else {
+          reject(err)
+        }
+      })
+    })
+  }
+
+  handleSubmit = (e) => {
+    e.preventDefault()
+
+    if (this.props.inputSubmit) {
+      this.props.inputSubmit()
+    }
+  }
+
+  render() {
+    const { getFieldDecorator } = this.props.form
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 6 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 18 }
+      }
+    }
+    return (
+      <Form {...formItemLayout} className="commontable-cospan-column-form" id="columncolspan">
+        <Row gutter={24}>
+          <Col span={12}>
+            <Form.Item label={this.props.dict['header.form.name']}>
+              {getFieldDecorator('label', {
+                initialValue: this.props.card.label,
+                rules: [
+                  {
+                    required: true,
+                    message: this.props.dict['form.required.input'] + this.props.dict['header.form.name'] + '!'
+                  },
+                  {
+                    max: formRule.input.max,
+                    message: formRule.input.message
+                  }
+                ]
+              })(<Input placeholder="" autoComplete="off" onPressEnter={this.handleSubmit} />)}
+            </Form.Item>
+          </Col>
+          <Col span={12}>
+            <Form.Item label={this.props.dict['header.form.type']}>
+              {getFieldDecorator('type', {
+                initialValue: this.props.dict['header.form.colspan'],
+                rules: [
+                  {
+                    required: true,
+                    message: this.props.dict['form.required.input'] + this.props.dict['header.form.type'] + '!'
+                  }
+                ]
+              })(<Input placeholder="" autoComplete="off" disabled={true}/>)}
+            </Form.Item>
+          </Col>
+          <Col span={12}>
+            <Form.Item label={this.props.dict['header.form.align']}>
+              {getFieldDecorator('Align', {
+                initialValue: this.props.card.Align,
+                rules: [
+                  {
+                    required: true,
+                    message: this.props.dict['form.required.select'] + this.props.dict['header.form.align'] + '!'
+                  }
+                ]
+              })(
+                <Select
+                  getPopupContainer={() => document.getElementById('columncolspan')}
+                >
+                  <Select.Option value="left">{this.props.dict['header.form.alignLeft']}</Select.Option>
+                  <Select.Option value="right">{this.props.dict['header.form.alignRight']}</Select.Option>
+                  <Select.Option value="center">{this.props.dict['header.form.alignCenter']}</Select.Option>
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+          <Col span={12}>
+            <Form.Item label={this.props.dict['header.form.columnWidth']}>
+              {getFieldDecorator('Width', {
+                initialValue: this.props.card.Width,
+                rules: [
+                  {
+                    required: true,
+                    message: this.props.dict['form.required.input'] + this.props.dict['header.form.columnWidth'] + '!'
+                  }
+                ]
+              })(<InputNumber min={1} max={1000} precision={0} />)}
+            </Form.Item>
+          </Col>
+          <Col span={12}>
+            <Form.Item label={this.props.dict['header.form.Hide']}>
+              {getFieldDecorator('Hide', {
+                initialValue: this.props.card.Hide,
+                rules: [
+                  {
+                    required: true,
+                    message: this.props.dict['form.required.select'] + this.props.dict['header.form.Hide'] + '!'
+                  }
+                ]
+              })(
+                <Radio.Group>
+                  <Radio value="true">{this.props.dict['header.form.true']}</Radio>
+                  <Radio value="false">{this.props.dict['header.form.false']}</Radio>
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col>
+          <Col span={12}>
+            <Form.Item label={this.props.dict['header.form.order']}>
+              {getFieldDecorator('order', {
+                initialValue: this.props.card.order,
+                rules: [
+                  {
+                    required: true,
+                    message: this.props.dict['form.required.select'] + this.props.dict['header.form.order'] + '!'
+                  }
+                ]
+              })(
+                <Select
+                  getPopupContainer={() => document.getElementById('columncolspan')}
+                >
+                  <Select.Option value="vertical">{this.props.dict['header.form.vertical']}</Select.Option>
+                  <Select.Option value="horizontal">{this.props.dict['header.form.horizontal']}</Select.Option>
+                  <Select.Option value="vertical2">{this.props.dict['header.form.vertical2']}</Select.Option>
+                  <Select.Option value="topPicBottomText">{this.props.dict['header.form.topPicBottomText']}</Select.Option>
+                  <Select.Option value="leftPicRightText">{this.props.dict['header.form.leftPicRightText']}</Select.Option>
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+          <Col span={24}>
+            <TransferForm dict={this.props.dict} columns={this.props.columns} ref="column-transfer" selected={this.props.card.sublist}/>
+          </Col>
+        </Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(MainSearch)
\ No newline at end of file
diff --git a/src/templates/sharecomponent/columncomponent/colspanform/index.scss b/src/templates/sharecomponent/columncomponent/colspanform/index.scss
new file mode 100644
index 0000000..d6690dc
--- /dev/null
+++ b/src/templates/sharecomponent/columncomponent/colspanform/index.scss
@@ -0,0 +1,8 @@
+.commontable-cospan-column-form {
+  min-height: 190px;
+  .ant-form-item {
+    .ant-input-number {
+      width: 100%;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/templates/sharecomponent/columncomponent/columnform/index.jsx b/src/templates/sharecomponent/columncomponent/columnform/index.jsx
new file mode 100644
index 0000000..e8674c3
--- /dev/null
+++ b/src/templates/sharecomponent/columncomponent/columnform/index.jsx
@@ -0,0 +1,376 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Input, Select, InputNumber, Radio, Tooltip, Icon, Cascader, notification } from 'antd'
+
+import { formRule } from '@/utils/option.js'
+import options from '@/store/options.js'
+import Api from '@/api'
+import './index.scss'
+
+const columnTypeOptions = {
+  text: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'prefix', 'postfix', 'matchVal', 'color', 'fieldlength', 'blacklist', 'linkmenu'],
+  number: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'decimal', 'format', 'prefix', 'postfix', 'match', 'matchVal', 'color', 'blacklist', 'linkmenu'],
+  textarea: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'prefix', 'postfix', 'matchVal', 'color', 'fieldlength', 'blacklist'],
+  picture: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'fieldlength', 'blacklist', 'scale', 'maxHeight']
+}
+
+class MainSearch extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,     // 瀛楀吀椤�
+    MenuID: PropTypes.any,
+    formlist: PropTypes.any,
+    card: PropTypes.any,
+    inputSubmit: PropTypes.any  // 鍥炶溅鎻愪氦浜嬩欢
+  }
+
+  state = {
+    formlist: null,
+    menulist: null
+  }
+
+  UNSAFE_componentWillMount () {
+    let _type = this.props.formlist.filter(form => form.key === 'type')[0].initVal
+    let _menulist = this.props.formlist.filter(form => form.key === 'linkmenu')[0] || ''
+
+    let _options = JSON.parse(JSON.stringify(columnTypeOptions[_type]))
+
+    this.setState({
+      menulist: _menulist.options || [],
+      formlist: this.props.formlist.map(item => {
+        item.hidden = !_options.includes(item.key)
+        if (item.key === 'matchVal' && (_type === 'text' || _type === 'textarea')) {
+          item.type = 'text'
+        } else if (item.key === 'matchVal' && _type === 'number') {
+          item.type = 'number'
+        }
+        return item
+      })
+    })
+  }
+
+  componentDidMount () {
+    const { card } = this.props
+
+    if (card.focus) {
+      try {
+        let _form = document.getElementById('label')
+        _form.select()
+      } catch {
+        console.warn('琛ㄥ崟focus澶辫触锛�')
+      }
+    }
+  }
+
+  typeChange = (key, value) => {
+    if (key === 'type') {
+      let _options = JSON.parse(JSON.stringify(columnTypeOptions[value]))
+
+      this.setState({
+        formlist: this.props.formlist.map(item => {
+          item.hidden = !_options.includes(item.key)
+          if (item.key === 'matchVal' && (value === 'text' || value === 'textarea')) {
+            item.type = 'text'
+          } else if (item.key === 'matchVal' && value === 'number') {
+            item.type = 'number'
+            item.initVal = ''
+            item.hidden = true
+          } else if (item.key === 'fieldlength') {
+            if (value === 'text') {
+              item.initVal = 50
+            } else {
+              item.initVal = 512
+            }
+            item.hidden = true
+          }
+          return item
+        })
+      }, () => {
+        this.setState({
+          formlist: this.props.formlist.map(item => {
+            if (item.key === 'matchVal' && value === 'number') {
+              item.hidden = false
+            } else if (item.key === 'fieldlength' && value !== 'number') {
+              item.hidden = false
+            }
+            return item
+          })
+        })
+      })
+    }
+  }
+
+  handleSubmit = (e) => {
+    e.preventDefault()
+
+    if (this.props.inputSubmit) {
+      this.props.inputSubmit()
+    }
+  }
+
+  getFields() {
+    const { getFieldDecorator } = this.props.form
+    const fields = []
+    this.state.formlist.forEach((item, index) => {
+      if (item.hidden) return
+
+      if (item.type === 'text') { // 鏂囨湰鎼滅储
+        let rules = []
+        if (item.key === 'field') {
+          rules = [{
+            pattern: formRule.field.pattern,
+            message: formRule.field.message
+          }, {
+            max: formRule.field.max,
+            message: formRule.field.maxMessage
+          }]
+        } else {
+          rules = [{
+            max: formRule.input.max,
+            message: formRule.input.message
+          }]
+        }
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" overlayClassName={item.tooltipClass} title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || '',
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  },
+                  ...rules
+                ]
+              })(<Input placeholder="" autoComplete="off" disabled={item.readonly} onPressEnter={this.handleSubmit} />)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'number') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" overlayClassName={item.tooltipClass} title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  }
+                ]
+              })(<InputNumber min={item.min} max={item.max} precision={item.decimal} />)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'select') { // 涓嬫媺鎼滅储
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || '',
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <Select
+                  showSearch
+                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                  onChange={(value) => {this.typeChange(item.key, value)}}
+                  getPopupContainer={() => document.getElementById('columnwinter')}
+                >
+                  {item.options.map((option, index) =>
+                    <Select.Option id={`${index}`} title={option.text} key={`${index}`} value={option.value}>
+                      {option.text}
+                    </Select.Option>
+                  )}
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'radio') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <Radio.Group>
+                  {
+                    item.options.map(option => {
+                      return (
+                        <Radio key={option.value} value={option.value}>{option.text}</Radio>
+                      )
+                    })
+                  }
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'multiselect') { // 澶氶��
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || []
+              })(
+                <Select
+                  showSearch
+                  mode="multiple"
+                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                >
+                  {item.options.map((option, i) =>
+                    <Select.Option id={i} key={i} value={option.value}>{option.text}</Select.Option>
+                  )}
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'cascader') { // 澶氶��
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || []
+              })(
+                <Cascader
+                  options={this.state.menulist}
+                  loadData={this.loadData}
+                  placeholder=""
+                  getPopupContainer={() => document.getElementById('columnwinter')}
+                />
+              )}
+            </Form.Item>
+          </Col>
+        )
+      }
+    })
+    return fields
+  }
+
+  loadData = selectedOptions => {
+    const { MenuID } = this.props
+    const targetOption = selectedOptions[selectedOptions.length - 1]
+    targetOption.loading = true
+
+    let _param = {
+      func: 'sPC_Get_FunMenu',
+      ParentID: targetOption.value,
+      systemType: options.systemType,
+      debug: 'Y'
+    }
+
+    Api.getSystemConfig(_param).then(result => {
+      if (result.status) {
+        targetOption.loading = false
+        targetOption.children = result.data.map(item => {
+          let submenu = {
+            value: item.ParentID,
+            label: item.MenuNameP,
+            children: item.FunMenu.map(cell => {
+              return {
+                value: cell.MenuID,
+                label: cell.MenuName,
+                MenuID: cell.MenuID,
+                MenuName: cell.MenuName,
+                MenuNo: cell.MenuNo,
+                Ot: cell.Ot,
+                PageParam: cell.PageParam,
+                LinkUrl: cell.LinkUrl,
+                disabled: cell.MenuID === MenuID
+              }
+            })
+          }
+
+          return submenu
+        })
+
+        this.setState({
+          menulist: [...this.state.menulist]
+        })
+      } else {
+        notification.warning({
+          top: 92,
+          message: result.message,
+          duration: 5
+        })
+        targetOption.loading = false
+      }
+    })
+  }
+
+  handleConfirm = () => {
+    const { menulist } = this.state
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          values.id = this.props.card.id
+          values.uuid = this.props.card.uuid
+          
+          if ((values.type === 'text' || values.type === 'number') && values.linkmenu && values.linkmenu.length > 0) {
+            let linkThdMenu = ''
+            menulist.forEach(menu => {
+              if (menu.value === values.linkmenu[0]) {
+                menu.children.forEach(item => {
+                  if (item.value === values.linkmenu[1]) {
+                    item.children.forEach(cell => {
+                      if (cell.value === values.linkmenu[2]) {
+                        linkThdMenu = cell
+                      }
+                    })
+                  }
+                })
+              }
+            })
+            values.linkThdMenu = linkThdMenu
+          }
+          
+          resolve(values)
+        } else {
+          reject(err)
+        }
+      })
+    })
+  }
+
+  render() {
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 6 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 18 }
+      }
+    }
+    return (
+      <Form {...formItemLayout} className="commontable-column-form" id="columnwinter">
+        <Row gutter={24}>{this.getFields()}</Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(MainSearch)
\ No newline at end of file
diff --git a/src/templates/sharecomponent/columncomponent/columnform/index.scss b/src/templates/sharecomponent/columncomponent/columnform/index.scss
new file mode 100644
index 0000000..fcf59ac
--- /dev/null
+++ b/src/templates/sharecomponent/columncomponent/columnform/index.scss
@@ -0,0 +1,19 @@
+.commontable-column-form {
+  min-height: 190px;
+  .ant-form-item {
+    .ant-input-number {
+      width: 100%;
+    }
+  }
+  .anticon-question-circle {
+    color: #c49f47;
+    position: relative;
+    left: -3px;
+  }
+  .ant-cascader-menus {
+    padding: 5px 0px;
+    .ant-cascader-menu:last-child {
+      padding-right: 3px;
+    }
+  }
+}
diff --git a/src/templates/sharecomponent/columncomponent/dragcolumn/card.jsx b/src/templates/sharecomponent/columncomponent/dragcolumn/card.jsx
new file mode 100644
index 0000000..a10ded7
--- /dev/null
+++ b/src/templates/sharecomponent/columncomponent/dragcolumn/card.jsx
@@ -0,0 +1,58 @@
+import React from 'react'
+import { useDrag, useDrop } from 'react-dnd'
+import { Icon } from 'antd'
+import './index.scss'
+
+const Card = ({ id, card, showfield, moveCard, findCard, editCard, delCard, hasDrop }) => {
+  const originalIndex = findCard(id).index
+  const [{ isDragging }, drag] = useDrag({
+    item: { type: 'columns', id, originalIndex },
+    collect: monitor => ({
+      isDragging: monitor.isDragging(),
+    }),
+  })
+  const [, drop] = useDrop({
+    accept: 'columns',
+    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
+
+  return (
+    <div className="page-card" style={{ flex: card.Width, opacity: opacity}}>
+      <div ref={node => drag(drop(node))}>
+        <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>
+      </div>
+      <Icon className="edit" title="edit" type="edit" onClick={() => editCard(id)} />
+      <Icon className="edit close" title="delete" type="close" onClick={() => delCard(id)} />
+    </div>
+  )
+}
+export default Card
diff --git a/src/templates/sharecomponent/columncomponent/dragcolumn/index.jsx b/src/templates/sharecomponent/columncomponent/dragcolumn/index.jsx
new file mode 100644
index 0000000..3c608b0
--- /dev/null
+++ b/src/templates/sharecomponent/columncomponent/dragcolumn/index.jsx
@@ -0,0 +1,165 @@
+import React, { useState } from 'react'
+import { useDrop } from 'react-dnd'
+import { is, fromJS } from 'immutable'
+import update from 'immutability-helper'
+import { Icon } from 'antd'
+import Utils from '@/utils/utils.js'
+import Card from './card'
+import './index.scss'
+
+const Container = ({list, setting, gridBtn, showfield, placeholder, handleList, handleMenu, handleGridBtn, deleteMenu }) => {
+  let target = null
+
+  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(_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 editCard = id => {
+    const { card } = findCard(id)
+    handleMenu(card)
+  }
+  
+
+  const delCard = id => {
+    const { card } = findCard(id)
+    deleteMenu(card)
+  }
+
+  const hasDrop = (item) => {
+    target = item
+  }
+
+  const [, drop] = useDrop({
+    accept: 'columns',
+    drop(item) {
+      if (item.hasOwnProperty('originalIndex')) {
+        return
+      }
+
+      let newcard = {}
+      newcard.uuid = Utils.getuuid()
+      newcard.focus = true
+      
+      newcard.Align = 'left'
+      newcard.label = 'label'
+      newcard.field = ''
+      newcard.Hide = 'false'
+      newcard.IsSort = 'true'
+      newcard.type = item.subType
+      newcard.Width = 120
+      if (item.subType === 'colspan') {
+        newcard.sublist = []
+        newcard.subfield = []
+        newcard.IsSort = 'false'
+        newcard.order = 'vertical'
+      }
+      
+      let targetId = cards.length > 0 ? cards[cards.length - 1].uuid : 0
+      if (target) {
+        targetId = target.uuid
+      }
+
+      const { index: overIndex } = findCard(`${targetId}`)
+      let targetIndex = overIndex
+
+      targetIndex++
+
+      const _cards = update(cards, { $splice: [[targetIndex, 0, newcard]] })
+
+      handleList(_cards, newcard)
+      target = null
+    }
+  })
+
+  let columns = []
+  let _colCards = []
+
+  // 杩囨护鍚堝苟鍒�
+    let _hideCol = []
+    cards.forEach(col => {
+      if (col.type === 'colspan' && col.sublist) {
+        _hideCol.push(...col.sublist)
+      }
+    })
+    cards.forEach(col => {
+      if (_hideCol.includes(col.uuid)) return
+
+      _colCards.push(col)
+    })
+
+  // 鏄剧ず鍒楀垎琛�
+  if (_colCards.length > 10) {
+    let number = Math.ceil(_colCards.length / Math.ceil(_colCards.length / 10))
+    for (let i = 0, len = _colCards.length; i < len; i += number) {
+      columns.push(_colCards.slice(i, i + number))
+    }
+  } else {
+    columns.push(_colCards)
+  }
+
+  return (
+    <div ref={drop} className="ant-row">
+      {columns.map((column, i) => (
+        <div key={i} className="column-box">
+          {/* 澶氶�� */}
+          {i === 0 && column.length > 0 && setting.tableType === 'checkbox' ?
+            <div className="page-card" style={{flex: 60}}>
+              <span className="ant-checkbox-inner"></span>
+            </div> : null
+          }
+          {/* 鍗曢�� */}
+          {i === 0 && column.length > 0 && setting.tableType === 'radio' ?
+            <div className="page-card" style={{flex: 60}}></div> : null
+          }
+          {column.map(card => (
+            <Card
+              key={card.uuid}
+              id={card.uuid}
+              card={card}
+              showfield={showfield}
+              moveCard={moveCard}
+              editCard={editCard}
+              delCard={delCard}
+              findCard={findCard}
+              hasDrop={hasDrop}
+            />
+          ))}
+          {i === (columns.length - 1) && gridBtn && gridBtn.display ?
+            <div className="page-card" style={{flex: gridBtn.Width}}>
+              <div style={{cursor: 'default'}}>
+                <span className="ant-table-header-column">
+                  <div className="ant-table-column-sorters" title={gridBtn.label} style={{textAlign: gridBtn.Align}}>
+                    <span className="ant-table-column-title">{gridBtn.label}</span>
+                  </div>
+                </span>
+              </div>
+              <Icon className="edit" type="edit" onClick={handleGridBtn}/>
+            </div> : null
+          }
+        </div>
+      ))}
+      
+      {cards.length === 0 ?
+        <div className="common-drawarea-placeholder">
+          {placeholder}
+        </div> : null
+      }
+    </div>
+  )
+}
+export default Container
diff --git a/src/templates/sharecomponent/columncomponent/dragcolumn/index.scss b/src/templates/sharecomponent/columncomponent/dragcolumn/index.scss
new file mode 100644
index 0000000..369ae98
--- /dev/null
+++ b/src/templates/sharecomponent/columncomponent/dragcolumn/index.scss
@@ -0,0 +1,6 @@
+.common-drawarea-placeholder {
+  width: 100%;
+  line-height: 65px;
+  text-align: center;
+  color: #bcbcbc;
+}
\ No newline at end of file
diff --git a/src/templates/sharecomponent/columncomponent/gridbtnform/index.jsx b/src/templates/sharecomponent/columncomponent/gridbtnform/index.jsx
new file mode 100644
index 0000000..09eae88
--- /dev/null
+++ b/src/templates/sharecomponent/columncomponent/gridbtnform/index.jsx
@@ -0,0 +1,218 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Input, Select, InputNumber, Radio } from 'antd'
+import { formRule } from '@/utils/option.js'
+import './index.scss'
+
+class MainSearch extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,     // 瀛楀吀椤�
+    card: PropTypes.any,
+    inputSubmit: PropTypes.any  // 鍥炶溅鎻愪氦浜嬩欢
+  }
+
+  state = {
+    formlist: [
+      {
+        type: 'text',
+        key: 'label',
+        label: this.props.dict['header.form.name'],
+        initVal: this.props.card.label,
+        required: true
+      },
+      {
+        type: 'select',
+        key: 'Align',
+        label: this.props.dict['header.form.align'],
+        initVal: this.props.card.Align,
+        required: true,
+        options: [{
+          MenuID: 'left',
+          text: this.props.dict['header.form.alignLeft']
+        }, {
+          MenuID: 'right',
+          text: this.props.dict['header.form.alignRight']
+        }, {
+          MenuID: 'center',
+          text: this.props.dict['header.form.alignCenter']
+        }]
+      },
+      {
+        type: 'number',
+        key: 'Width',
+        decimal: 0,
+        label: this.props.dict['header.form.columnWidth'],
+        initVal: this.props.card.Width,
+        required: true
+      },
+      {
+        type: 'select',
+        key: 'style',
+        label: this.props.dict['header.form.style'],
+        initVal: this.props.card.style,
+        required: true,
+        options: [{
+          MenuID: 'button',
+          text: this.props.dict['header.form.button']
+        }, {
+          MenuID: 'text',
+          text: this.props.dict['header.form.text']
+        }]
+      },
+      {
+        type: 'select',
+        key: 'show',
+        label: this.props.dict['header.form.order'],
+        initVal: this.props.card.show,
+        required: true,
+        options: [{
+          MenuID: 'horizontal',
+          text: this.props.dict['header.form.horizontal']
+        }, {
+          MenuID: 'vertical',
+          text: this.props.dict['header.form.vertical']
+        }]
+      }
+    ]
+  }
+
+  handleSubmit = (e) => {
+    e.preventDefault()
+
+    if (this.props.inputSubmit) {
+      this.props.inputSubmit()
+    }
+  }
+
+  getFields() {
+    const { getFieldDecorator } = this.props.form
+    const fields = []
+    this.state.formlist.forEach((item, index) => {
+      if (item.type === 'text') { // 鏂囨湰鎼滅储
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || '',
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  },
+                  {
+                    max: formRule.input.max,
+                    message: formRule.input.message
+                  }
+                ]
+              })(<Input placeholder="" autoComplete="off" disabled={item.readonly} onPressEnter={this.handleSubmit} />)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'number') { // 鏂囨湰鎼滅储
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || '',
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  }
+                ]
+              })(<InputNumber min={1} max={1000} precision={item.decimal} />)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'select') { // 涓嬫媺鎼滅储
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || '',
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <Select
+                  showSearch
+                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                  getPopupContainer={() => document.getElementById('gridbtncolumnwinter')}
+                >
+                  {item.options.map(option =>
+                    <Select.Option id={option.MenuID} title={option.text} key={option.MenuID} value={option.MenuID}>
+                      {option.text}
+                    </Select.Option>
+                  )}
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'radio') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <Radio.Group>
+                  {
+                    item.options.map(option => {
+                      return (
+                        <Radio key={option.MenuID} value={option.MenuID}>{option.text}</Radio>
+                      )
+                    })
+                  }
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      }
+    })
+    return fields
+  }
+
+  handleConfirm = () => {
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          resolve({...this.props.card, ...values})
+        } else {
+          reject(err)
+        }
+      })
+    })
+  }
+
+  render() {
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 6 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 18 }
+      }
+    }
+    return (
+      <Form {...formItemLayout} className="commontable-gridbtn-column-form" id="gridbtncolumnwinter">
+        <Row gutter={24}>{this.getFields()}</Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(MainSearch)
\ No newline at end of file
diff --git a/src/templates/sharecomponent/columncomponent/gridbtnform/index.scss b/src/templates/sharecomponent/columncomponent/gridbtnform/index.scss
new file mode 100644
index 0000000..abb563c
--- /dev/null
+++ b/src/templates/sharecomponent/columncomponent/gridbtnform/index.scss
@@ -0,0 +1,8 @@
+.commontable-gridbtn-column-form {
+  min-height: 190px;
+  .ant-form-item {
+    .ant-input-number {
+      width: 100%;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/templates/sharecomponent/columncomponent/index.jsx b/src/templates/sharecomponent/columncomponent/index.jsx
new file mode 100644
index 0000000..aa07790
--- /dev/null
+++ b/src/templates/sharecomponent/columncomponent/index.jsx
@@ -0,0 +1,437 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Icon, Tooltip, Modal, notification, Switch, message, Spin } from 'antd'
+
+import Api from '@/api'
+import options from '@/store/options.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import { getColumnForm } from '@/templates/zshare/formconfig'
+
+import ColumnForm from './columnform'
+import ColspanForm from './colspanform'
+import GridBtnForm from './gridbtnform'
+import DragElement from './dragcolumn'
+import './index.scss'
+
+const { confirm } = Modal
+
+// **鎮茶鑰呭線寰�姝g‘锛屼箰瑙傝�呭線寰�鎴愬姛
+class ColumnComponent extends Component {
+  static propTpyes = {
+    menu: PropTypes.object,          // 涓夌骇鑿滃崟淇℃伅
+    config: PropTypes.object,        // 閰嶇疆淇℃伅
+    pasteContent: PropTypes.object,  // 绮樿创閰嶇疆淇℃伅
+    sysRoles: PropTypes.array,       // 瑙掕壊鍒楄〃锛屾潈闄愬垎閰�
+    updatecolumn: PropTypes.func     // 鏇存柊
+  }
+
+  state = {
+    dict: (!localStorage.getItem('lang') || localStorage.getItem('lang') === 'zh-CN') ? zhCN : enUS,
+    columnlist: null,    // 鏄剧ず鍒�
+    loading: false,      // 鏌ヨ鏄剧ず鍒楀叧鑱旇彍鍗�
+    showField: false,    // 鏄剧ず鍒楀瓧娈�
+    modaltype: '',       // 妯℃�佹鎺у埗
+    card: null           // 缂栬緫涓厓绱�
+  }
+
+  /**
+   * @description 鏄剧ず鍒楀垵濮嬪寲
+   */
+  UNSAFE_componentWillMount () {
+    this.setState({
+      columnlist: fromJS(this.props.config.columns).toJS()
+    })
+  }
+
+  /**
+   * @description 鐩戝惉鍒版樉绀哄垪澶嶅埗鏃讹紝瑙﹀彂鏄剧ず鍒楃紪杈�
+   */
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    const { columnlist } = this.state
+
+    if (
+      nextProps.pasteContent &&
+      columnlist.length === 0 &&
+      nextProps.pasteContent.columns &&
+      nextProps.pasteContent.copyType === 'columns' &&
+      nextProps.pasteContent.columns.length > 0
+    ) {
+      this.setState({columnlist: nextProps.pasteContent.columns})
+    } else if (!is(fromJS(nextProps.config.columns), fromJS(this.props.config.columns)) && !is(fromJS(nextProps.config.columns), fromJS(columnlist))) {
+      this.setState({columnlist: nextProps.config.columns})
+    }
+  }
+
+  /**
+   * @description 鏄剧ず鍒楅『搴忚皟鏁达紝鎴栨嫋鎷芥坊鍔�
+   */
+  handleList = (list, card) => {
+    const { config } = this.props
+
+    if (card) {
+      this.setState({columnlist: list})
+      this.handleColumn(card)
+    } else {
+      this.setState({columnlist: list})
+      this.props.updatecolumn({...config, search: list})
+    }
+  }
+
+  /**
+   * @description 鏄剧ず鍒椾笌鍚堝苟鍒楃紪杈戯紝鑾峰彇琛ㄥ崟淇℃伅
+   */
+  handleColumn = (card) => {
+    const { menu } = this.props
+
+    if (card.type !== 'colspan') {
+      let menulist = menu.fstMenuList.map(item => {
+        return {
+          value: item.MenuID,
+          label: item.text,
+          isLeaf: false
+        }
+      })
+
+      if ((card.type === 'text' || card.type === 'number') && card.linkmenu && card.linkmenu.length > 0) {
+        let _param = {
+          func: 'sPC_Get_FunMenu',
+          ParentID: card.linkmenu[0],
+          systemType: options.systemType,
+          debug: 'Y'
+        }
+
+        this.setState({
+          loading: true
+        })
+    
+        Api.getSystemConfig(_param).then(result => {
+          if (result.status) {
+            menulist = menulist.map(item => {
+              if (item.value === card.linkmenu[0]) {
+                item.children = result.data.map(item => {
+                  let submenu = {
+                    value: item.ParentID,
+                    label: item.MenuNameP,
+                    children: item.FunMenu.map(cell => {
+                      return {
+                        value: cell.MenuID,
+                        label: cell.MenuName,
+                        MenuID: cell.MenuID,
+                        MenuName: cell.MenuName,
+                        MenuNo: cell.MenuNo,
+                        Ot: cell.Ot,
+                        PageParam: cell.PageParam,
+                        LinkUrl: cell.LinkUrl,
+                        disabled: cell.MenuID === menu.MenuID
+                      }
+                    })
+                  }
+
+                  return submenu
+                })
+              }
+              return item
+            })
+          } else {
+            notification.warning({
+              top: 92,
+              message: result.message,
+              duration: 5
+            })
+          }
+
+          this.setState({
+            loading: false,
+            modaltype: 'columns',
+            card: card,
+            formlist: getColumnForm(card, this.props.sysRoles, menulist)
+          })
+        })
+      } else {
+        this.setState({
+          modaltype: 'columns',
+          card: card,
+          formlist: getColumnForm(card, this.props.sysRoles, menulist)
+        })
+      }
+    } else {
+      this.setState({
+        modaltype: 'colspan',
+        card: card
+      })
+    }
+  }
+
+  /**
+   * @description 鎿嶄綔鍒楃紪杈�
+   */
+  handleGridBtn = () => {
+    this.setState({
+      modaltype: 'gridbtn'
+    })
+  }
+
+  /**
+   * @description 鍙栨秷淇濆瓨锛屽鏋滃厓绱犱负鏂版坊鍏冪礌锛屽垯浠庡簭鍒椾腑鍒犻櫎
+   */
+  editModalCancel = () => {
+    const { card } = this.state
+
+    if (card.focus) {
+      let _columnlist = fromJS(this.state.columnlist).toJS()
+
+      _columnlist = _columnlist.filter(item => item.uuid !== card.uuid)
+
+      this.setState({
+        card: null,
+        modaltype: '',
+        columnlist: _columnlist
+      })
+    } else {
+      this.setState({
+        card: null,
+        modaltype: ''
+      })
+    }
+  }
+
+  /**
+   * @description 鎼滅储淇敼鍚庢彁浜や繚瀛�
+   * 1銆佸幓闄ょ郴缁熼粯璁ゆ樉绀哄垪
+   * 2銆佸瓧娈靛強鎻愮ず鏂囧瓧閲嶅鏍¢獙
+   * 3銆佹洿鏂颁笅鎷夎彍鍗曞彲閫夐泦鍚�
+   * 4銆佷笅鎷夎彍鍗曟暟鎹簮璇硶楠岃瘉
+   */
+  handleSubmit = () => {
+    const { config } = this.props
+    const { modaltype } = this.state
+
+    let _columnlist = fromJS(this.state.columnlist).toJS()
+
+    if (modaltype === 'columns' || modaltype === 'colspan') {
+      this.columnFormRef.handleConfirm().then(res => {
+        let fieldrepet = false // 瀛楁閲嶅
+        let labelrepet = false // 鎻愮ず鏂囧瓧閲嶅
+
+        _columnlist = _columnlist.filter(item => !item.origin || item.uuid === res.uuid) // 鍘婚櫎鍒濆鍒�
+
+        _columnlist = _columnlist.map(item => {
+          if (item.uuid !== res.uuid && res.field && item.field) {
+            if (item.field === res.field) {
+              fieldrepet = true
+            } else if (item.label === res.label) {
+              labelrepet = true
+            }
+          }
+
+          if (item.uuid === res.uuid) {
+            return res
+          } else {
+            return item
+          }
+        })
+
+        if (fieldrepet) {
+          notification.warning({
+            top: 92,
+            message: this.state.dict['model.field.exist'] + ' !',
+            duration: 5
+          })
+          return
+        } else if (labelrepet) {
+          notification.warning({
+            top: 92,
+            message: this.state.dict['model.name.exist'] + ' !',
+            duration: 5
+          })
+          return
+        }
+
+        this.setState({
+          columnlist: _columnlist,
+          modaltype: ''
+        })
+        this.props.updatecolumn({...config, columns: _columnlist})
+      })
+    } else if (modaltype === 'gridbtn') {
+      this.gridBtnFormRef.handleConfirm().then(res => {
+        this.setState({
+          modaltype: ''
+        })
+
+        this.props.updatecolumn({...config, gridBtn: res})
+      })
+    }
+  }
+
+  /**
+   * @description 鏄剧ず鍒楀垹闄�
+   */
+  deleteElement = (card) => {
+    const { config } = this.props
+    const { dict } = this.state
+    let _this = this
+
+    confirm({
+      content: dict['model.confirm'] + dict['model.delete'] + ` - ${card.label} 锛焋,
+      okText: dict['model.confirm'],
+      cancelText: this.state.dict['header.cancel'],
+      onOk() {
+        let _columnlist = fromJS(_this.state.columnlist).toJS()
+
+        _columnlist = _columnlist.filter(item => item.uuid !== card.uuid)
+
+        _this.setState({
+          columnlist: _columnlist
+        })
+        _this.props.updatecolumn({...config, columns: _columnlist})
+      },
+      onCancel() {}
+    })
+  }
+
+  /**
+   * @description 鏄剧ず鍒楀鍒�
+   */
+  copycolumn = () => {
+    const { columnlist } = this.state
+
+    let oInput = document.createElement('input')
+    let val = {
+      copyType: 'columns',
+      columns: columnlist
+    }
+
+    oInput.value = window.btoa(window.encodeURIComponent(JSON.stringify(val)))
+    document.body.appendChild(oInput)
+    oInput.select()
+    document.execCommand('Copy')
+    oInput.className = 'oInput'
+    oInput.style.display = 'none'
+
+    message.success('澶嶅埗鎴愬姛銆�')
+
+    document.body.removeChild(oInput)
+  }
+
+  /**
+   * @description 鏄剧ず鍒楀瓧娈靛悕鏄剧ず鎴栭殣钘忔帶鍒�
+   */
+  onFieldChange = () => {
+    const { showField, columnlist } = this.state
+
+    if (!showField) {
+      let fields = []
+      columnlist.forEach(col => {
+        if (col.field) {
+          fields.push(col.field)
+        }
+      })
+
+      fields = fields.join(',')
+
+      let textArea = document.createElement('textarea')
+      textArea.value = fields
+      document.body.appendChild(textArea)
+      textArea.select()
+
+      try {
+        document.execCommand('copy')
+        document.body.removeChild(textArea)
+      } catch (err) {
+        document.body.removeChild(textArea)
+      }
+    }
+
+    this.setState({
+      showField: !showField
+    })
+  }
+
+  render() {
+    const { config } = this.props
+    const { modaltype, columnlist, dict, card } = this.state
+
+    return (
+      <div className="model-table-column-list">
+        <Tooltip placement="bottomLeft" overlayClassName="middle" title={dict['model.tooltip.column.guide']}>
+          <Icon type="question-circle" />
+        </Tooltip>
+        {columnlist && columnlist.length > 0 ?
+          <Icon className="column-copy" title="copy" type="copy" onClick={this.copycolumn} /> : null
+        }
+        <Switch checkedChildren="寮�" unCheckedChildren="鍏�" defaultChecked={this.state.showField} onChange={this.onFieldChange} />
+        <DragElement
+          list={columnlist}
+          setting={config.setting}
+          gridBtn={config.gridBtn}
+          handleList={this.handleList}
+          handleMenu={this.handleColumn}
+          deleteMenu={this.deleteElement}
+          handleGridBtn={this.handleGridBtn}
+          showfield={this.state.showField}
+          placeholder={this.state.dict['header.form.column.placeholder']}
+        />
+        {/* 鏄剧ず鍒楃紪杈� */}
+        <Modal
+          title={dict['header.modal.column.edit']}
+          visible={modaltype === 'columns'}
+          width={750}
+          maskClosable={false}
+          onOk={this.handleSubmit}
+          onCancel={this.editModalCancel}
+          destroyOnClose
+        >
+          <ColumnForm
+            dict={dict}
+            card={card}
+            MenuID={this.props.menu.MenuID}
+            inputSubmit={this.handleSubmit}
+            formlist={this.state.formlist}
+            wrappedComponentRef={(inst) => this.columnFormRef = inst}
+          />
+        </Modal>
+        {/* 鍚堝苟鍒楃紪杈� */}
+        <Modal
+          title={dict['header.modal.colspan.edit']}
+          visible={modaltype === 'colspan'}
+          width={750}
+          maskClosable={false}
+          onOk={this.handleSubmit}
+          onCancel={this.editModalCancel}
+          destroyOnClose
+        >
+          <ColspanForm
+            dict={dict}
+            card={card}
+            inputSubmit={this.handleSubmit}
+            columns={columnlist}
+            wrappedComponentRef={(inst) => this.columnFormRef = inst}
+          />
+        </Modal>
+        {/* 鎿嶄綔鍒楃紪杈� */}
+        <Modal
+          title={dict['header.modal.gridbtn.edit']}
+          visible={modaltype === 'gridbtn'}
+          width={700}
+          maskClosable={false}
+          onOk={this.handleSubmit}
+          onCancel={this.editModalCancel}
+          destroyOnClose
+        >
+          <GridBtnForm
+            dict={dict}
+            inputSubmit={this.handleSubmit}
+            card={config.gridBtn}
+            wrappedComponentRef={(inst) => this.gridBtnFormRef = inst}
+          />
+        </Modal>
+        {this.state.loading && <Spin size="large" />}
+      </div>
+    )
+  }
+}
+
+export default ColumnComponent
\ No newline at end of file
diff --git a/src/templates/sharecomponent/columncomponent/index.scss b/src/templates/sharecomponent/columncomponent/index.scss
new file mode 100644
index 0000000..663681f
--- /dev/null
+++ b/src/templates/sharecomponent/columncomponent/index.scss
@@ -0,0 +1,85 @@
+.model-table-column-list {
+  position: relative;
+  padding: 0px 20px 100px;
+  .ant-switch {
+    position: absolute;
+    right: 20px;
+    top: -10px;
+  }
+  .column-copy {
+    position: absolute;
+    font-size: 16px;
+    right: 75px;
+    top: -7px;
+    color: #26C281;
+  }
+  > .ant-row {
+    background: #fafafa;
+    border-radius: 4px;
+    min-height: 47px;
+    border: 1px solid #e8e8e8;
+    .column-box {
+      display: flex;
+    }
+    .column-box:not(:first-child) {
+      border-top: 1px solid #e8e8e8;
+    }
+    .page-card {
+      position: relative;
+      padding: 0px;
+      min-height: 45px;
+      > div {
+        padding: 12px 0px 0px;
+        cursor: move;
+        height: 100%;
+        .ant-table-column-sorters {
+          padding: 0px 8px 12px;
+        }
+        .ant-table-column-fields {
+          padding: 0px 8px 5px;
+        }
+      }
+      .ant-table-column-sorter {
+        position: relative;
+        display: inline-block;
+        width: 24px;
+        font-size: 12px;
+        color: #bfbfbf;
+        .anticon-caret-up {
+          position: relative;
+          left: 10px;
+          top: -3px;
+        }
+        .anticon-caret-down {
+          position: relative;
+          left: -2px;
+          top: 3px;
+        }
+      }
+      .edit {
+        position: absolute;
+        left: 0;
+        top: 0px;
+        color: #1890ff;
+        cursor: pointer;
+        display: none;
+      }
+      .edit.close {
+        left: 20px;
+        color: #ff4d4f;
+      }
+      .ant-checkbox-inner {
+        margin-top: 14px;
+        margin-left: calc(50% - 8px);
+      }
+    }
+    .page-card:hover {
+      .edit {
+        display: inline-block;
+      }
+    }
+    .page-card:not(:last-child) {
+      border-right: 1px solid #e8e8e8;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/templates/sharecomponent/fieldscomponent/editcard/index.jsx b/src/templates/sharecomponent/fieldscomponent/editcard/index.jsx
new file mode 100644
index 0000000..c0c579d
--- /dev/null
+++ b/src/templates/sharecomponent/fieldscomponent/editcard/index.jsx
@@ -0,0 +1,157 @@
+import React, {Component} from 'react'
+import { Row, Col, Icon, Radio, Input, Button } from 'antd'
+import './index.scss'
+
+const { Search } = Input
+
+class EditCardCell extends Component {
+  constructor(props) {
+    super(props)
+
+    let _type = props.card.type
+    if (props.type === 'columns') {
+      if (_type === 'date' || _type === 'datetime') {
+        _type = 'text'
+      }
+    } else if (props.type === 'search') {
+      if (_type === 'number') {
+        _type = 'text'
+      } else if (_type === 'datetime') {
+        _type = 'daterange'
+      }
+    } else if (props.type === 'form') {
+      
+    }
+
+    this.state = {
+      card: {...props.card, type: _type},
+      type: props.type
+    }
+  }
+
+  changeSelect = () => {
+    const { card } = this.state
+    this.setState({
+      card: {...card, selected: !card.selected}
+    }, () => {
+      this.props.changeCard(this.state.card)
+    })
+  }
+
+  changeType = (e) => {
+    const { card } = this.state
+    this.setState({
+      card: {...card, type: e.target.value}
+    }, () => {
+      this.props.changeCard(this.state.card)
+    })
+  }
+
+  render() {
+    const { card, type } = this.state
+    return (
+      <div className={'ant-card ant-card-bordered ' + (card.selected ? 'selected' : '')} >
+        <div className="base" onClick={this.changeSelect}>
+          <Icon type="check" />
+          <p title={card.field}>{this.props.dict['header.form.field']}锛� <span>{card.field}</span></p>
+          <p title={card.label}>{this.props.dict['header.form.name']}锛� <span>{card.label}</span></p>
+        </div>
+        {type === 'search' ?
+          <Radio.Group onChange={this.changeType} value={card.type} disabled={!card.selected}>
+            <Radio value="text">text</Radio>
+            <Radio value="select">select</Radio>
+            <Radio value="daterange">dateRange</Radio>
+          </Radio.Group> : null
+        }
+        {type === 'columns' ?
+          <Radio.Group onChange={this.changeType} value={card.type} disabled={!card.selected}>
+            <Radio value="text">text</Radio>
+            <Radio value="number">number</Radio>
+            <Radio value="picture">picture</Radio>
+          </Radio.Group> : null
+        }
+        {type === 'form' ?
+          <Radio.Group onChange={this.changeType} value={card.type} disabled={!card.selected}>
+            <Radio value="text">text</Radio>
+            <Radio value="number">number</Radio>
+            <Radio value="select">select</Radio>
+            <Radio value="date">date</Radio>
+          </Radio.Group> : null
+        }
+      </div>
+    )
+  }
+}
+
+class EditCard extends Component {
+  constructor(props) {
+    super(props)
+
+    this.state = {
+      dataSource: props.data,
+      selectCards: props.data.filter(item => item.selected),
+      type: props.type,
+      searchKey: '',
+      loading: false
+    }
+  }
+
+  changeCard = (item) => {
+    let cards = JSON.parse(JSON.stringify(this.state.selectCards))
+
+    if (!item.selected) {
+      cards = cards.filter(card => card.field !== item.field)
+    } else {
+      cards.push(item)
+    }
+
+    this.setState({
+      selectCards: cards
+    })
+  }
+
+  reset = () => {
+    this.setState({
+      searchKey: '',
+      loading: true
+    }, () => {
+      this.setState({
+        loading: false
+      })
+    })
+  }
+
+  render() {
+    const { dataSource, type, loading } = this.state
+
+    return (
+      <div className="common-modal-edit-card">
+        <Row className="search-row">
+          <Col span={8}>
+            {!loading ? <Search placeholder={this.props.dict['header.form.field.placeholder']} onSearch={value => {this.setState({searchKey: value})}} enterButton /> : null}
+          </Col>
+          <Col span={8}>
+            <Button onClick={this.reset}>
+              {this.props.dict['header.reset']}
+            </Button>
+          </Col>
+        </Row>
+        <Row>
+          {dataSource.map((item, index) => {
+            if (item.field.toLowerCase().indexOf(this.state.searchKey.toLowerCase()) >= 0) {
+              return (
+                <Col key={index} span={8}>
+                  <EditCardCell ref={'cellCard' + index} type={type} card={item} dict={this.props.dict} changeCard={this.changeCard} />
+                </Col>
+              )
+            } else {
+              return ''
+            }
+          })}
+        </Row>
+      </div>
+    )
+  }
+}
+
+export default EditCard
\ No newline at end of file
diff --git a/src/templates/sharecomponent/fieldscomponent/editcard/index.scss b/src/templates/sharecomponent/fieldscomponent/editcard/index.scss
new file mode 100644
index 0000000..a504e4a
--- /dev/null
+++ b/src/templates/sharecomponent/fieldscomponent/editcard/index.scss
@@ -0,0 +1,49 @@
+.common-modal-edit-card {
+  margin-left: -10px;
+  margin-right: -10px;
+  .ant-col {
+    padding: 10px;
+    .ant-card {
+      padding: 0px 10px 10px;
+      p {
+        margin-bottom: 5px;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+      }
+      label {
+        margin-right: 15px;
+        span.ant-radio + * {
+          padding-right: 0px;
+          padding-left: 4px;
+        }
+      }
+      .anticon {
+        position: absolute;
+        top: 10px;
+        right: 10px;
+        opacity: 0.4;
+      }
+      .base {
+        padding-top: 10px;
+        cursor: pointer;
+      }
+    }
+    .ant-card.selected {
+      border-color: #1890ff;
+      box-shadow: 0px 0px 4px #1890ff;
+      .anticon {
+        opacity: 1;
+        color: #1890ff;
+      }
+      p {
+        color: #1890ff;
+      }
+    }
+  }
+  .search-row {
+    .ant-col {
+      padding-top: 0px;
+    }
+  }
+}
diff --git a/src/templates/sharecomponent/fieldscomponent/index.jsx b/src/templates/sharecomponent/fieldscomponent/index.jsx
new file mode 100644
index 0000000..31db78f
--- /dev/null
+++ b/src/templates/sharecomponent/fieldscomponent/index.jsx
@@ -0,0 +1,252 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { fromJS } from 'immutable'
+import { Button, Modal, Empty, notification } from 'antd'
+
+import Utils from '@/utils/utils.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import EditCard from './editcard'
+
+import './index.scss'
+
+// **鎮茶鑰呭線寰�姝g‘锛屼箰瑙傝�呭線寰�鎴愬姛
+class FieldsComponent extends Component {
+  static propTpyes = {
+    type: PropTypes.string,          // 鎼滅储鏉′欢娣诲姞銆佹樉绀哄垪娣诲姞
+    config: PropTypes.object,        // 瀹瑰櫒Id
+    tableFields: PropTypes.string,   // 宸查�夎〃瀛楁闆�
+    updatefield: PropTypes.func
+  }
+
+  state = {
+    dict: (!localStorage.getItem('lang') || localStorage.getItem('lang') === 'zh-CN') ? zhCN : enUS,
+    fields: [],          // 瀛楁闆�
+    tableVisible: false,    // 妯℃�佹鎺у埗
+  }
+
+  queryField = () => {
+    const { type, config, tableFields } = this.props
+    // 鍒ゆ柇鏄惁宸查�夋嫨琛ㄥ悕
+    if (!config.tables || config.tables.length === 0) {
+      notification.warning({
+        top: 92,
+        message: '璇烽�夋嫨琛ㄥ悕锛�',
+        duration: 5
+      })
+      return
+    }
+
+    // 琛ㄥ瓧娈甸泦杞负map鏁版嵁
+    let columns = new Map()
+    tableFields.forEach(table => {
+      table.columns.forEach(column => {
+        columns.set(column.field, column)
+      })
+    })
+
+    if (type === 'search') {
+      // 娣诲姞鎼滅储鏉′欢锛屽瓧娈甸泦涓瓨鍦ㄦ悳绱㈡潯浠跺瓧娈碉紝浣跨敤鎼滅储鏉′欢瀵硅薄鏇挎崲瀛楁闆嗭紝璁剧疆鏁版嵁绫诲瀷
+      config.search.forEach(item => {
+        if (columns.has(item.field)) {
+          let _datatype = columns.get(item.field).datatype
+          columns.set(item.field, {...item, selected: true, datatype: _datatype})
+        }
+      })
+    } else if (type === 'columns') {
+      // 娣诲姞鏄剧ず鍒楋紝瀛楁闆嗕腑瀛樺湪鏄剧ず鍒楀瓧娈碉紝浣跨敤鏄剧ず鍒楀璞℃浛鎹㈠瓧娈甸泦锛岃缃暟鎹被鍨�
+      config.columns.forEach(item => {
+        if (columns.has(item.field)) {
+          let _datatype = columns.get(item.field).datatype
+          columns.set(item.field, {...item, selected: true, datatype: _datatype})
+        }
+      })
+    }
+
+    // 鏄剧ず瀛楁闆嗗脊绐�
+    this.setState({
+      tableVisible: true,
+      fields: [...columns.values()]
+    })
+  }
+
+  addFieldSubmit = () => {
+    const { type } = this.props
+    // 瀛楁闆嗕负绌猴紝鍏抽棴寮圭獥
+    if (!this.state.fields || this.state.fields.length === 0) {
+      this.setState({
+        tableVisible: false
+      })
+    }
+
+    let config = fromJS(this.props.config).toJS()
+
+    // 鑾峰彇宸查�夊瓧娈甸泦鍚�
+    let cards = this.refs.searchcard.state.selectCards
+    let columnsMap = new Map()
+    cards.forEach(card => {
+      columnsMap.set(card.field, card)
+    })
+
+    let items = []
+    if (type === 'search') {
+      config.search.forEach(item => {
+        if (columnsMap.has(item.field)) {
+          let cell = columnsMap.get(item.field)
+
+          if (cell.selected && cell.type === item.type) { // 鏁版嵁鏈慨鏀�
+            items.push(item)
+          } else if (cell.selected) { // 鏁版嵁绫诲瀷淇敼
+            if (cell.type === 'select') {
+              item.match = '='
+            } else if (cell.type === 'daterange') {
+              item.match = 'between'
+            } else {
+              cell.type = 'text'
+              item.match = 'like'
+            }
+            
+            item.type = cell.type
+            item.initval = ''
+            items.push(item)
+          }
+          columnsMap.delete(item.field)
+        } else if (!item.origin) {
+          items.push(item)
+        }
+      })
+
+      let _columns = [...columnsMap.values()]
+
+      _columns.forEach(item => {
+        if (item.selected) {
+          let _match = ''
+          if (item.type === 'select') {
+            _match = '='
+          } else if (item.type === 'daterange') {
+            _match = 'between'
+          } else {
+            item.type = 'text'
+            _match = 'like'
+          }
+
+          let newcard = {
+            uuid: Utils.getuuid(),
+            label: item.label,
+            field: item.field,
+            initval: '',
+            type: item.type,
+            resourceType: '0',
+            setAll: 'false',
+            options: [],
+            dataSource: '',
+            linkField: '',
+            valueField: '',
+            valueText: '',
+            orderBy: '',
+            orderType: 'asc',
+            match: _match,
+            display: 'dropdown'
+          }
+
+          items.push(newcard)
+        }
+      })
+    } else if (type === 'columns') {
+      config.columns.forEach(item => {
+        if (columnsMap.has(item.field)) {
+          let cell = columnsMap.get(item.field)
+
+          if (cell.selected) {
+            items.push(item)
+          }
+          columnsMap.delete(item.field)
+        } else if (!item.origin) {
+          items.push(item)
+        }
+      })
+
+      let _columns = [...columnsMap.values()]
+
+      _columns.forEach(item => {
+        if (item.selected) {
+          let newcard = {
+            uuid: Utils.getuuid(),
+            Align: 'left',
+            label: item.label,
+            field: item.field,
+            Hide: 'false',
+            IsSort: item.type === 'picture' ? 'false' : 'true',
+            type: item.type,
+            Width: 120
+          }
+
+          items.push(newcard)
+        }
+      })
+    }
+
+    let _config = null
+
+    if (type === 'search') {
+      _config = {...this.props.config, search: items}
+    } else if (type === 'columns') {
+      _config = {...this.props.config, columns: items}
+    }
+
+    if (_config) {
+      this.props.updatefield(_config)
+
+      notification.success({
+        top: 92,
+        message: '鎿嶄綔鎴愬姛',
+        duration: 2
+      })
+    }
+  }
+
+
+  render() {
+    const { type } = this.props
+    const { dict, fields } = this.state
+
+    let label = ''
+    if (type === 'search') {
+      label = dict['header.menu.search.add']
+    } else if (type === 'columns') {
+      label = dict['header.menu.column.add']
+    }
+
+    return (
+      <div>
+        <Button type="primary" block onClick={this.queryField}>{label}</Button>
+        {/* 鏍规嵁瀛楁鍚嶆坊鍔犳樉绀哄垪鍙婃悳绱㈡潯浠� */}
+        <Modal
+          wrapClassName="model-table-fieldmanage-modal"
+          title={dict['model.edit']}
+          visible={this.state.tableVisible}
+          width={'65vw'}
+          maskClosable={false}
+          style={{minWidth: '900px', maxWidth: '1200px'}}
+          cancelText={dict['header.close']}
+          onOk={this.addFieldSubmit}
+          onCancel={() => { // 鍙栨秷娣诲姞
+            this.setState({
+              tableVisible: false
+            })
+          }}
+          destroyOnClose
+        >
+          {fields.length > 0 ?
+            <EditCard data={fields} ref="searchcard" type={type} dict={dict} /> : null
+          }
+          {(!fields || fields.length === 0) &&
+            <Empty />
+          }
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default FieldsComponent
\ No newline at end of file
diff --git a/src/templates/sharecomponent/fieldscomponent/index.scss b/src/templates/sharecomponent/fieldscomponent/index.scss
new file mode 100644
index 0000000..eb8645e
--- /dev/null
+++ b/src/templates/sharecomponent/fieldscomponent/index.scss
@@ -0,0 +1,27 @@
+.model-table-fieldmanage-modal {
+  .ant-modal {
+    top: 50px;
+    padding-bottom: 5px;
+    .ant-modal-body {
+      max-height: calc(100vh - 190px);
+      overflow-y: auto;
+      .ant-empty {
+        margin: 15vh 8px;
+      }
+    }
+    .ant-modal-body::-webkit-scrollbar {
+      width: 7px;
+    }
+    .ant-modal-body::-webkit-scrollbar-thumb {
+      border-radius: 5px;
+      box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
+      background: rgba(0, 0, 0, 0.13);
+    }
+    .ant-modal-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);
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/templates/sharecomponent/searchcomponent/dragsearch/card.jsx b/src/templates/sharecomponent/searchcomponent/dragsearch/card.jsx
new file mode 100644
index 0000000..87b61b3
--- /dev/null
+++ b/src/templates/sharecomponent/searchcomponent/dragsearch/card.jsx
@@ -0,0 +1,101 @@
+import React from 'react'
+import { useDrag, useDrop } from 'react-dnd'
+import { Icon, Select, DatePicker, Input } from 'antd'
+import moment from 'moment'
+import './index.scss'
+
+const { MonthPicker, WeekPicker, RangePicker } = DatePicker
+
+const Card = ({ id, card, moveCard, copyCard, findCard, editCard, delCard, hasDrop }) => {
+  const originalIndex = findCard(id).index
+  const [{ isDragging }, drag] = useDrag({
+    item: { type: 'search', id, originalIndex },
+    collect: monitor => ({
+      isDragging: monitor.isDragging(),
+    }),
+  })
+  const [, drop] = useDrop({
+    accept: 'search',
+    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
+
+  let _defaultValue = '' // 涓嬫媺鎼滅储銆佹椂闂磋寖鍥寸被鍨嬶紝鍒濆鍊奸渶瑕侀澶勭悊
+
+  if (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 = 'All'
+    }
+  } else if (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]
+      }
+    }
+  }
+
+  return (
+    <div className="page-card" style={{ opacity: opacity}}>
+      <div ref={node => drag(drop(node))}>
+        <div className="ant-row ant-form-item">
+          <div className="ant-col ant-form-item-label ant-col-xs-24 ant-col-sm-8">
+            <label className={card.required === 'true' ? 'ant-form-item-required' : ''} title={card.label}>{card.label}</label>
+          </div>
+          <div className="ant-col ant-form-item-control-wrapper ant-col-xs-24 ant-col-sm-16">
+            {card.type === 'text' ?
+              <Input style={{marginTop: '4px'}} value={card.initval} /> : null
+            }
+            {(card.type === 'multiselect' || card.type === 'select' || card.type === 'link') ?
+              <Select value={_defaultValue}></Select> : null
+            }
+            {card.type === 'date' ?
+              <DatePicker value={card.initval ? moment().subtract(card.initval, 'days') : null} /> : null
+            }
+            {card.type === 'dateweek' ?
+              <WeekPicker value={card.initval ? moment().subtract(card.initval * 7, 'days') : null} /> : null
+            }
+            {card.type === 'datemonth' ?
+              <MonthPicker value={card.initval ? moment().subtract(card.initval, 'month') : null} /> : null
+            }
+            {card.type === 'daterange' ?
+              <RangePicker
+                className="data-range"
+                placeholder={['BeginTime', 'EndTime']}
+                renderExtraFooter={() => 'extra footer'}
+                value={_defaultValue}
+              /> : null
+            }
+            <div className="input-mask"></div>
+          </div>
+        </div>
+      </div>
+      <Icon className="edit" title="edit" type="edit" onClick={() => editCard(id)} />
+      <Icon className="edit copy" title="copy" type="copy" onClick={() => copyCard(id)} />
+      <Icon className="edit close" title="delete" type="close" onClick={() => delCard(id)} />
+    </div>
+  )
+}
+export default Card
diff --git a/src/templates/sharecomponent/searchcomponent/dragsearch/index.jsx b/src/templates/sharecomponent/searchcomponent/dragsearch/index.jsx
new file mode 100644
index 0000000..0281328
--- /dev/null
+++ b/src/templates/sharecomponent/searchcomponent/dragsearch/index.jsx
@@ -0,0 +1,155 @@
+import React, { useState } from 'react'
+import { useDrop } from 'react-dnd'
+import { is, fromJS } from 'immutable'
+import update from 'immutability-helper'
+import { Col } from 'antd'
+import Utils from '@/utils/utils.js'
+import Card from './card'
+import './index.scss'
+
+const Container = ({list, placeholder, handleList, handleMenu, deleteMenu }) => {
+  let target = null
+
+  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(_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 editCard = id => {
+    const { card } = findCard(id)
+    handleMenu(card)
+  }
+  
+
+  const delCard = id => {
+    const { card } = findCard(id)
+    deleteMenu(card)
+  }
+
+  const copyCard = id => {
+    const { card } = findCard(id)
+    let copycard = fromJS(card).toJS()
+
+    copycard.uuid = Utils.getuuid()
+    copycard.origin = false
+    copycard.copyType = 'search'
+    copycard.label = copycard.label + '(copy)'
+    copycard.focus = true
+
+    let _val = fromJS(copycard).toJS()
+
+    try {
+      _val.uuid = Utils.getuuid()
+      _val = window.btoa(window.encodeURIComponent(JSON.stringify(_val)))
+    } catch {
+      console.warn('Stringify Failure')
+      _val = ''
+    }
+
+    if (_val) {
+      let oInput = document.createElement('input')
+      oInput.value = _val
+      document.body.appendChild(oInput)
+      oInput.select()
+      document.execCommand('Copy')
+      document.body.removeChild(oInput)
+    }
+
+    const { index: overIndex } = findCard(id)
+
+    const _cards = update(cards, { $splice: [[overIndex + 1, 0, copycard]] })
+
+    handleList(_cards, copycard)
+  }
+
+  const hasDrop = (item) => {
+    target = item
+  }
+
+  const [, drop] = useDrop({
+    accept: 'search',
+    drop(item) {
+      if (item.hasOwnProperty('originalIndex')) {
+        return
+      }
+
+      let newcard = {}
+      newcard.uuid = Utils.getuuid()
+      newcard.focus = true
+      
+      let _match = 'like'
+      if (item.subType === 'select' || item.subType === 'link') {
+        _match = '='
+      } else if (item.subType === 'date' || item.subType === 'datemonth') {
+        _match = '>='
+      } else if (item.subType === 'dateweek' || item.subType === 'daterange') {
+        _match = 'between'
+      }
+      
+      newcard.label = 'label'
+      newcard.initval = ''
+      newcard.type = item.subType
+      newcard.resourceType = '0'
+      newcard.options = []
+      newcard.setAll = 'false'
+      newcard.orderType = 'asc'
+      newcard.match = _match
+      newcard.display = 'dropdown'
+      
+      let targetId = cards.length > 0 ? cards[cards.length - 1].uuid : 0
+      if (target) {
+        targetId = target.uuid
+      }
+
+      const { index: overIndex } = findCard(`${targetId}`)
+      let targetIndex = overIndex
+
+      targetIndex++
+
+      const _cards = update(cards, { $splice: [[targetIndex, 0, newcard]] })
+
+      handleList(_cards, newcard)
+      target = null
+    }
+  })
+
+  return (
+    <div ref={drop} className="ant-row">
+      {cards.map(card => (
+        <Col key={card.uuid} span={card.ratio || 6}>
+          <Card
+            id={`${card.uuid}`}
+            card={card}
+            moveCard={moveCard}
+            copyCard={copyCard}
+            editCard={editCard}
+            delCard={delCard}
+            findCard={findCard}
+            hasDrop={hasDrop}
+          />
+        </Col>
+      ))}
+      
+      {cards.length === 0 ?
+        <div className="common-drawarea-placeholder">
+          {placeholder}
+        </div> : null
+      }
+    </div>
+  )
+}
+export default Container
diff --git a/src/templates/sharecomponent/searchcomponent/dragsearch/index.scss b/src/templates/sharecomponent/searchcomponent/dragsearch/index.scss
new file mode 100644
index 0000000..369ae98
--- /dev/null
+++ b/src/templates/sharecomponent/searchcomponent/dragsearch/index.scss
@@ -0,0 +1,6 @@
+.common-drawarea-placeholder {
+  width: 100%;
+  line-height: 65px;
+  text-align: center;
+  color: #bcbcbc;
+}
\ No newline at end of file
diff --git a/src/templates/sharecomponent/searchcomponent/index.jsx b/src/templates/sharecomponent/searchcomponent/index.jsx
new file mode 100644
index 0000000..fa84f28
--- /dev/null
+++ b/src/templates/sharecomponent/searchcomponent/index.jsx
@@ -0,0 +1,280 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Icon, Tooltip, Modal, notification } from 'antd'
+import moment from 'moment'
+
+import Api from '@/api'
+import Utils from '@/utils/utils.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import { getSearchForm } from '@/templates/zshare/formconfig'
+
+import SearchForm from './searchform'
+import DragElement from './dragsearch'
+import './index.scss'
+
+const { confirm } = Modal
+
+// **鎮茶鑰呭線寰�姝g‘锛屼箰瑙傝�呭線寰�鎴愬姛
+class SearchComponent extends Component {
+  static propTpyes = {
+    menu: PropTypes.object,          // 褰撳墠鑿滃崟淇℃伅
+    config: PropTypes.object,        // 閰嶇疆淇℃伅
+    pasteContent: PropTypes.object,  // 绮樿创閰嶇疆淇℃伅
+    optionLibs: PropTypes.any,       // 涓嬫媺瀛楀吀
+    sysRoles: PropTypes.array,       // 瑙掕壊鍒楄〃锛岄粦鍚嶅崟
+    updatesearch: PropTypes.func     // 鏇存柊
+  }
+
+  state = {
+    dict: (!localStorage.getItem('lang') || localStorage.getItem('lang') === 'zh-CN') ? zhCN : enUS,
+    searchlist: null,    // 鎼滅储鏉′欢闆�
+    sqlVerifing: false,  // sql楠岃瘉涓�
+    visible: false,      // 妯℃�佹鎺у埗
+    card: null           // 缂栬緫涓厓绱�
+  }
+
+  /**
+   * @description 鎼滅储鏉′欢鍒濆鍖�
+   */
+  UNSAFE_componentWillMount () {
+    this.setState({
+      searchlist: fromJS(this.props.config.search).toJS()
+    })
+  }
+
+  /**
+   * @description 鐩戝惉鍒版悳绱㈡潯浠跺鍒舵椂锛岃Е鍙戞悳绱㈡潯浠剁紪杈�
+   */
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    const { searchlist } = this.state
+
+    if (nextProps.pasteContent && nextProps.pasteContent.copyType === 'search') {
+      this.setState({searchlist: [...searchlist, nextProps.pasteContent]})
+      this.handleSearch(nextProps.pasteContent)
+    } else if (!is(fromJS(nextProps.config.search), fromJS(this.props.config.search)) && !is(fromJS(nextProps.config.search), fromJS(searchlist))) {
+      this.setState({searchlist: nextProps.config.search})
+    }
+  }
+
+  /**
+   * @description 鎼滅储鏉′欢椤哄簭璋冩暣锛屾垨鎷栨嫿娣诲姞
+   */
+  handleList = (list, card) => {
+    const { config } = this.props
+
+    if (card) {
+      this.setState({searchlist: list})
+      this.handleSearch(card)
+    } else {
+      this.setState({searchlist: list})
+      this.props.updatesearch({...config, search: list})
+    }
+  }
+
+  /**
+   * @description 鎼滅储鏉′欢缂栬緫锛岃幏鍙栨悳绱㈡潯浠惰〃鍗曚俊鎭�
+   */
+  handleSearch = (card) => {
+    this.setState({
+      visible: true,
+      card: card,
+      formlist: getSearchForm(card, this.props.sysRoles)
+    })
+  }
+
+  /**
+   * @description 鍙栨秷淇濆瓨锛屽鏋滃厓绱犱负鏂版坊鍏冪礌锛屽垯浠庡簭鍒椾腑鍒犻櫎
+   */
+  editModalCancel = () => {
+    const { card } = this.state
+
+    if (card.focus) {
+      let searchlist = fromJS(this.state.searchlist).toJS()
+
+      searchlist = searchlist.filter(item => item.uuid !== card.uuid)
+
+      this.setState({
+        card: null,
+        searchlist: searchlist,
+        visible: false
+      })
+    } else {
+      this.setState({
+        card: null,
+        visible: false
+      })
+    }
+  }
+
+  /**
+   * @description 鎼滅储淇敼鍚庢彁浜や繚瀛�
+   * 1銆佸幓闄ょ郴缁熼粯璁ゆ悳绱㈡潯浠�
+   * 2銆佸瓧娈靛強鎻愮ず鏂囧瓧閲嶅鏍¢獙
+   * 3銆佹洿鏂颁笅鎷夎彍鍗曞彲閫夐泦鍚�
+   * 4銆佷笅鎷夎彍鍗曟暟鎹簮璇硶楠岃瘉
+   */
+  handleSubmit = () => {
+    const { optionLibs, menu, config } = this.props
+    let _searchlist = fromJS(this.state.searchlist).toJS()
+
+    this.searchFormRef.handleConfirm().then(res => {
+      let fieldrepet = false // 瀛楁閲嶅
+      let labelrepet = false // 鎻愮ず鏂囧瓧閲嶅
+
+      _searchlist = _searchlist.filter(item => !item.origin || item.uuid === res.uuid) // 鍘婚櫎绯荤粺椤�
+
+      _searchlist = _searchlist.map(item => { // 鏁版嵁鏇存柊鍙婇噸澶嶆娴�
+        if (item.uuid !== res.uuid && res.field && item.field) {
+          if (item.field === res.field) {
+            fieldrepet = true
+          } else if (item.label === res.label) {
+            labelrepet = true
+          }
+        }
+
+        if (item.uuid === res.uuid) {
+          return res
+        } else {
+          return item
+        }
+      })
+
+      if (fieldrepet) {
+        notification.warning({
+          top: 92,
+          message: this.state.dict['model.field.exist'] + ' !',
+          duration: 5
+        })
+        return
+      } else if (labelrepet) {
+        notification.warning({
+          top: 92,
+          message: this.state.dict['model.name.exist'] + ' !',
+          duration: 5
+        })
+        return
+      }
+
+      if ( res.options && res.options.length > 0 ) { // 涓嬫媺鑿滃崟鍙�夐泦鍚�
+        optionLibs.set(menu.MenuID + res.uuid, {
+          uuid: menu.MenuID + res.uuid,
+          label: res.label,
+          parname: menu.MenuName,
+          type: 'search',
+          options: res.options
+        })
+      }
+
+      if ((res.type === 'select' || res.type === 'multiselect' || res.type === 'link') && res.resourceType === '1' && /\s/.test(res.dataSource)) {
+        this.setState({
+          sqlVerifing: true
+        })
+
+        let param = {
+          func: 's_debug_sql',
+          LText: res.dataSource
+        }
+        param.LText = Utils.formatOptions(param.LText)
+        param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
+        param.secretkey = Utils.encrypt(param.LText, param.timestamp)
+
+        if (window.GLOB.mainSystemApi && res.database === 'sso') {
+          param.rduri = window.GLOB.mainSystemApi
+        }
+        
+        Api.getLocalConfig(param).then(result => {
+          if (result.status) {
+            this.setState({
+              sqlVerifing: false,
+              searchlist: _searchlist,
+              visible: false
+            })
+            this.props.updatesearch({...config, search: _searchlist}, optionLibs)
+          } else {
+            this.setState({sqlVerifing: false})
+            
+            Modal.error({
+              title: result.message
+            })
+          }
+        })
+      } else {
+        this.setState({
+          searchlist: _searchlist,
+          visible: false
+        })
+        this.props.updatesearch({...config, search: _searchlist}, optionLibs)
+      }
+    })
+  }
+
+  /**
+   * @description 鎼滅储鏉′欢鍒犻櫎
+   */
+  deleteElement = (card) => {
+    const { config } = this.props
+    const { dict } = this.state
+    let _this = this
+
+    confirm({
+      content: dict['model.confirm'] + dict['model.delete'] + ` - ${card.label} 锛焋,
+      okText: dict['model.confirm'],
+      cancelText: this.state.dict['header.cancel'],
+      onOk() {
+        let _searchlist = fromJS(_this.state.searchlist).toJS()
+
+        _searchlist = _searchlist.filter(item => item.uuid !== card.uuid)
+
+        _this.setState({
+          searchlist: _searchlist
+        }, () => {
+          _this.props.updatesearch({...config, search: _searchlist})
+        })
+      },
+      onCancel() {}
+    })
+  }
+
+  render() {
+    const { dict, searchlist, visible, sqlVerifing, card } = this.state
+
+    return (
+      <div className="model-table-search-list">
+        <Tooltip placement="bottomLeft" overlayClassName="middle" title={dict['model.tooltip.search.guide']}>
+          <Icon type="question-circle" />
+        </Tooltip>
+        <DragElement
+          list={searchlist}
+          handleList={this.handleList}
+          handleMenu={this.handleSearch}
+          deleteMenu={this.deleteElement}
+          placeholder={dict['header.form.search.placeholder']}
+        />
+        {/* 缂栬緫鎼滅储鏉′欢 */}
+        <Modal
+          title={dict['model.searchCriteria'] + '-' + (card && card.copyType === 'search' ?  dict['model.copy'] : dict['model.edit'])}
+          visible={visible}
+          width={750}
+          maskClosable={false}
+          onOk={this.handleSubmit}
+          confirmLoading={sqlVerifing}
+          onCancel={this.editModalCancel}
+          destroyOnClose
+        >
+          <SearchForm
+            dict={dict}
+            card={this.state.card}
+            formlist={this.state.formlist}
+            inputSubmit={this.handleSubmit}
+            optionLibs={this.props.optionLibs}
+            wrappedComponentRef={(inst) => this.searchFormRef = inst}
+          />
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default SearchComponent
\ No newline at end of file
diff --git a/src/templates/sharecomponent/searchcomponent/index.scss b/src/templates/sharecomponent/searchcomponent/index.scss
new file mode 100644
index 0000000..2463343
--- /dev/null
+++ b/src/templates/sharecomponent/searchcomponent/index.scss
@@ -0,0 +1,84 @@
+.model-table-search-list {
+  padding: 1px 24px 20px;
+  min-height: 87px;
+  border-bottom: 1px solid #d9d9d9;
+  > .ant-row {
+    min-height: 65px;
+  }
+  .ant-row .ant-col-6 {
+    padding: 0 12px!important;
+  }
+  .ant-row.ant-form-item .ant-col {
+    padding: 0;
+  }
+  .page-card {
+    position: relative;
+    background: #ffffff;
+    border-radius: 2px;
+    padding-top: 15px;
+    .ant-form-item {
+      cursor: move;
+      display: flex;
+      margin-bottom: 0px;
+      .ant-form-item-label {
+        height: 40px;
+        label {
+          width: 100%;
+          cursor: move;
+          overflow: hidden;
+          display: inline-block;
+          text-overflow: ellipsis;
+          white-space: nowrap;
+        }
+      }
+      .ant-form-item-control-wrapper {
+        flex: 1 1;
+        .ant-select {
+          width: 100%;
+          margin-top: 4px;
+        }
+        .ant-calendar-picker {
+          margin-top: 4px;
+        }
+        .input-mask {
+          position: absolute;
+          top: 0;
+          left: 0;
+          right: 0;
+          bottom: 0;
+          opacity: 0;
+          z-index: 2;
+        }
+        .data-range .ant-calendar-picker-input {
+          padding: 4px 20px 4px 5px;
+          font-size: 13px;
+        }
+      }
+    }
+    .edit {
+      position: absolute;
+      left: 0;
+      top: 5px;
+      color: #1890ff;
+      cursor: pointer;
+      display: none;
+    }
+    .edit.copy {
+      left: 20px;
+      color: #26C281;
+    }
+    .edit.close {
+      left: 40px;
+      color: #ff4d4f;
+    }
+  }
+  .page-card:hover {
+    .edit {
+      display: inline-block;
+    }
+  }
+  .ant-calendar-picker {
+    min-width: 100px!important;
+    width: 100%;
+  }
+}
\ No newline at end of file
diff --git a/src/templates/sharecomponent/searchcomponent/searcheditable/index.jsx b/src/templates/sharecomponent/searchcomponent/searcheditable/index.jsx
new file mode 100644
index 0000000..8abe02b
--- /dev/null
+++ b/src/templates/sharecomponent/searchcomponent/searcheditable/index.jsx
@@ -0,0 +1,265 @@
+import React, {Component} from 'react'
+import { is, fromJS } from 'immutable'
+import { Table, Input, Button, Popconfirm, Form, Icon } from 'antd'
+import Utils from '@/utils/utils.js'
+import './index.scss'
+
+const EditableContext = React.createContext()
+
+const EditableRow = ({ form, index, ...props }) => (
+  <EditableContext.Provider value={form}>
+    <tr {...props} />
+  </EditableContext.Provider>
+)
+
+const EditableFormRow = Form.create()(EditableRow)
+
+class EditableCell extends Component {
+  state = {
+    editing: false
+  }
+
+  toggleEdit = () => {
+    const editing = !this.state.editing
+    this.setState({ editing }, () => {
+      if (editing && this.input && this.input.select) {
+        this.input.select()
+      } else if (editing && this.input && this.input.focus) {
+        this.input.focus()
+      }
+    })
+  }
+
+  save = e => {
+    const { record, handleSave } = this.props
+    this.form.validateFields((error, values) => {
+      handleSave({ ...record, ...values })
+      if (error && error[e.currentTarget.id]) {
+        return
+      }
+      this.toggleEdit()
+    })
+  }
+
+  renderCell = form => {
+    this.form = form
+    const { children, dataIndex, record } = this.props
+    const { editing } = this.state
+    return editing ? (
+      <Form.Item style={{ margin: 0 }}>
+        {form.getFieldDecorator(dataIndex, {
+          rules: [
+            {
+              required: true,
+              message: 'NOT NULL.',
+            },
+          ],
+          initialValue: record[dataIndex]
+        })(<Input ref={node => (this.input = node)} autoComplete="off" onPressEnter={this.save} onBlur={this.save} />)}
+      </Form.Item>
+    ) : (
+      <div
+        className="editable-cell-value-wrap"
+        onClick={this.toggleEdit}
+      >
+        {children}
+      </div>
+    )
+  }
+
+  render() {
+    const {
+      editable,
+      dataIndex,
+      title,
+      record,
+      index,
+      handleSave,
+      children,
+      ...restProps
+    } = this.props
+    return (
+      <td {...restProps}>
+        {editable ? (
+          <EditableContext.Consumer style={{padding: 0}}>{this.renderCell}</EditableContext.Consumer>
+        ) : (
+          children
+        )}
+      </td>
+    )
+  }
+}
+
+class EditTable extends Component {
+  constructor(props) {
+    super(props)
+    let columns = [
+      {
+        title: 'Value',
+        dataIndex: 'Value',
+        width: props.type === 'link' ? '27%' : '40%',
+        editable: true
+      },
+      {
+        title: 'Text',
+        dataIndex: 'Text',
+        width: props.type === 'link' ? '27%' : '40%',
+        editable: true
+      },
+      {
+        title: 'Action',
+        align: 'center',
+        dataIndex: 'operation',
+        render: (text, record) =>
+          this.state.dataSource.length >= 1 ? (
+            <Popconfirm title="Sure to delete?" onConfirm={() => this.handleDelete(record.key)}>
+              <span style={{color: '#1890ff', cursor: 'pointer'}}><Icon type="delete" /></span>
+            </Popconfirm>
+          ) : null,
+      }
+    ]
+
+    if (props.type === 'link') {
+      columns.unshift({
+        title: 'ParentID',
+        dataIndex: 'ParentID',
+        width: '27%',
+        editable: true
+      })
+    }
+
+    this.state = {
+      columns: columns,
+      dataSource: props.data,
+      count: props.data.length,
+      type: props.type
+    }
+  }
+
+  handleDelete = key => {
+    const dataSource = [...this.state.dataSource]
+    this.setState({ dataSource: dataSource.filter(item => item.key !== key) })
+  }
+
+  handleAdd = () => {
+    const { type, count, dataSource } = this.state
+    const newData = {
+      key: Utils.getuuid(),
+      Value: `${count}`,
+      Text: `${count}`
+    }
+    if (type === 'link') {
+      newData.ParentID = `${count}`
+    }
+    this.setState({
+      dataSource: [...dataSource, newData],
+      count: count + 1
+    })
+  }
+
+  handleSave = row => {
+    const newData = [...this.state.dataSource]
+    const index = newData.findIndex(item => row.key === item.key)
+    const item = newData[index]
+    newData.splice(index, 1, {
+      ...item,
+      ...row
+    })
+    this.setState({ dataSource: newData })
+  }
+
+  resetColumn = (type) => {
+    let columns = [
+      {
+        title: 'Value',
+        dataIndex: 'Value',
+        width: type === 'link' ? '27%' : '40%',
+        editable: true
+      },
+      {
+        title: 'Text',
+        dataIndex: 'Text',
+        width: type === 'link' ? '27%' : '40%',
+        editable: true
+      },
+      {
+        title: 'Action',
+        align: 'center',
+        dataIndex: 'operation',
+        render: (text, record) =>
+          this.state.dataSource.length >= 1 ? (
+            <Popconfirm title="Sure to delete?" onConfirm={() => this.handleDelete(record.key)}>
+              <span style={{color: '#1890ff', cursor: 'pointer'}}><Icon type="delete" /></span>
+            </Popconfirm>
+          ) : null,
+      }
+    ]
+
+    if (type === 'link') {
+      columns.unshift({
+        title: 'ParentID',
+        dataIndex: 'ParentID',
+        width: '27%',
+        editable: true
+      })
+    }
+
+    this.setState({
+      columns: columns,
+      type: type
+    })
+  }
+
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    if (this.props.type !== nextProps.type) {
+      this.resetColumn(nextProps.type)
+    } else if (!is(fromJS(this.props.data), fromJS(nextProps.data))) {
+      this.setState({
+        dataSource: nextProps.data,
+        count: nextProps.data.length
+      })
+    }
+  }
+
+  render() {
+    const { dataSource } = this.state
+    const components = {
+      body: {
+        row: EditableFormRow,
+        cell: EditableCell
+      }
+    }
+    const columns = this.state.columns.map(col => {
+      if (!col.editable) {
+        return col
+      }
+      return {
+        ...col,
+        onCell: record => ({
+          record,
+          editable: col.editable,
+          dataIndex: col.dataIndex,
+          title: col.title,
+          handleSave: this.handleSave,
+        })
+      }
+    })
+    return (
+      <div className="common-modal-edit-table">
+        <Button onClick={this.handleAdd} type="primary" className="add-row">
+          Add
+        </Button>
+        <Table
+          components={components}
+          rowClassName={() => 'editable-row'}
+          bordered
+          dataSource={dataSource}
+          columns={columns}
+          pagination={false}
+        />
+      </div>
+    )
+  }
+}
+
+export default EditTable
\ No newline at end of file
diff --git a/src/templates/sharecomponent/searchcomponent/searcheditable/index.scss b/src/templates/sharecomponent/searchcomponent/searcheditable/index.scss
new file mode 100644
index 0000000..f8f0942
--- /dev/null
+++ b/src/templates/sharecomponent/searchcomponent/searcheditable/index.scss
@@ -0,0 +1,36 @@
+.common-modal-edit-table {
+  .add-row {
+    position: absolute;
+    z-index: 1;
+    right: 12px;
+    top: -40px;
+  }
+  .ant-table-thead > tr > th {
+    padding: 10px 16px;
+  }
+  .ant-table-tbody > tr > td {
+    padding: 0px 16px;
+  }
+  .editable-cell-value-wrap {
+    cursor: pointer;
+    height: 40px;
+    width: 100px;
+    display: table-cell;
+    vertical-align: middle;
+    word-wrap: break-word;
+    word-break: break-word;
+    .ant-input {
+      height: 30px;
+      padding: 0 11px;
+    }
+  }
+  .ant-form-item-control-wrapper {
+    width: 100%;
+  }
+  .ant-table-placeholder {
+    padding: 5px 16px;
+    .ant-empty-normal {
+      margin: 0;
+    }
+  }
+}
diff --git a/src/templates/sharecomponent/searchcomponent/searchform/index.jsx b/src/templates/sharecomponent/searchcomponent/searchform/index.jsx
new file mode 100644
index 0000000..e7941ec
--- /dev/null
+++ b/src/templates/sharecomponent/searchcomponent/searchform/index.jsx
@@ -0,0 +1,475 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Input, Select, Icon, Radio, notification, Tooltip, InputNumber } from 'antd'
+import { dateOptions, matchReg, formRule } from '@/utils/option.js'
+import EditTable from '../searcheditable'
+import Utils from '@/utils/utils.js'
+import './index.scss'
+
+const { TextArea } = Input
+
+class MainSearch extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,     // 瀛楀吀椤�
+    formlist: PropTypes.any,    // 琛ㄥ崟
+    optionLibs: PropTypes.any,  // 鑷畾涔変笅鎷夐泦
+    card: PropTypes.object,     // 鎼滅储鏉′欢淇℃伅
+    inputSubmit: PropTypes.any  // 鍥炶溅鎻愪氦浜嬩欢
+  }
+
+  state = {
+    openType: null,          // 鎼滅储鏉′欢鏄剧ず绫诲瀷
+    resourceType: null,      // 涓嬫媺鎼滅储鏃讹紝閫夐」鏉ユ簮绫诲瀷
+    formlist: null           // 琛ㄥ崟
+  }
+
+  /**
+   * @description 琛ㄥ崟棰勫鐞�
+   * 1銆佹牴鎹〃鍗曠被鍨嬶紝鏄剧ず琛ㄥ崟鍙紪杈戦」
+   * 2銆佷笅鎷夐�夋嫨锛屾牴鎹暟鎹簮绫诲瀷鏄剧ず鐩稿叧閰嶇疆
+   */
+  UNSAFE_componentWillMount () {
+    const { formlist, optionLibs } = this.props
+
+    let type = formlist.filter(cell => cell.key === 'type')[0].initVal
+    let resourceType = formlist.filter(cell => cell.key === 'resourceType')[0].initVal
+    let _options = ['label', 'field', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required']                // 榛樿鏄剧ず椤�
+
+    if ((type === 'multiselect' || type === 'select' || type === 'link') && resourceType === '0') {        // 涓嬫媺閫夋嫨绫诲瀷銆侀�夐」涓鸿嚜瀹氫箟璧勬簮
+      _options = [..._options, 'resourceType', 'options', 'display', 'quick']
+    } else if ((type === 'multiselect' || type === 'select' || type === 'link') && resourceType === '1') { // 涓嬫媺閫夋嫨绫诲瀷銆侀�夐」涓哄悗鍙版暟鎹簮涓幏鍙�
+      _options = [..._options, 'resourceType', 'dataSource', 'valueField', 'valueText', 'orderBy', 'orderType', 'display', 'database']
+    }
+
+    if (type === 'select' || type === 'link') {
+      _options.push('setAll')
+    }
+
+    if (type === 'link') { // 鍏宠仈绫诲瀷銆佸鍔犲叧鑱斾笂绾х殑瀛楁鍚�
+      _options = [..._options, 'linkField']
+    }
+    
+    this.setState({
+      openType: type,
+      resourceType: resourceType,
+      formlist: formlist.map(form => {
+        // 琛ㄥ崟涓哄垵濮嬪�煎瓧娈碉紝涓旀暟鎹被鍨嬪睘浜庢椂闂寸被鍨嬫椂锛岃缃垵濮嬪�间负涓嬫媺閫夋嫨锛屽苟閲嶇疆閫夋嫨椤�
+        if (form.key === 'initval' && dateOptions.hasOwnProperty(type)) {
+          form.options = dateOptions[type]
+          form.type = 'select'
+        }
+        // 琛ㄥ崟涓哄尮閰嶅瓧娈垫椂锛屾牴鎹笉鍚岀殑绫诲瀷锛屾樉绀哄搴旂殑鍖归厤瑙勫垯
+        if (form.key === 'match') {
+          if (type === 'text') {
+            form.options = matchReg.text
+          } else if (type === 'multiselect') {
+            form.options = matchReg.multiselect
+          } else if (type === 'select' || type === 'link') {
+            form.options = matchReg.select
+          } else if (type === 'date') {
+            form.options = matchReg.date
+          } else if (type === 'datemonth') {
+            form.options = matchReg.datemonth
+          } else if (type === 'dateweek' || type === 'daterange') {
+            form.options = matchReg.daterange
+          }
+        } else if (form.key === 'quick') {
+          form.options = [...optionLibs.values()].map(cell => {
+            return {
+              value: cell.uuid,
+              text: cell.label + '(' + cell.parname + ')'
+            }
+          })
+        }
+        form.hidden = !_options.includes(form.key)
+        return form
+      })
+    })
+  }
+
+  componentDidMount () {
+    const { card } = this.props
+
+    if (card.focus) {
+      try {
+        let _form = document.getElementById('label')
+        _form.select()
+      } catch {
+        console.warn('琛ㄥ崟focus澶辫触锛�')
+      }
+    }
+  }
+
+  /**
+   * @description 鎼滅储鏉′欢绫诲瀷鍒囨崲
+   */
+  openTypeChange = (key, value) => {
+    const { resourceType } = this.state
+
+    if (key === 'type') {
+      let _options = ['label', 'field', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required']
+
+      if ((value === 'multiselect' || value === 'select' || value === 'link') && resourceType === '0') {        // 涓嬫媺閫夋嫨绫诲瀷銆侀�夐」涓鸿嚜瀹氫箟璧勬簮
+        _options = [..._options, 'resourceType', 'options', 'display', 'quick']
+      } else if ((value === 'multiselect' || value === 'select' || value === 'link') && resourceType === '1') { // 涓嬫媺閫夋嫨绫诲瀷銆侀�夐」涓哄悗鍙版暟鎹簮涓幏鍙�
+        _options = [..._options, 'resourceType', 'dataSource', 'valueField', 'valueText', 'orderBy', 'orderType', 'display', 'database']
+      }
+
+      if (value === 'select' || value === 'link') {
+        _options.push('setAll')
+      }
+      
+      if (value === 'link') {
+        _options = [..._options, 'linkField']
+      }
+
+      this.setState({
+        openType: value,
+        formlist: this.state.formlist.map(form => {
+          form.hidden = !_options.includes(form.key)            // 闅愯棌琛ㄥ崟
+
+          if (form.key === 'initval') {
+            if (dateOptions.hasOwnProperty(value)) { // 鏍规嵁鎼滅储鏉′欢绫诲瀷锛岄�夋嫨鍒濆鍊肩殑绫诲瀷鍙婃暟鎹�
+              form.options = dateOptions[value]
+              form.type = 'select'
+            } else {
+              form.type = 'text'
+            }
+            form.initVal = ''                                    // 鎼滅储鏉′欢绫诲瀷鍒囨崲鏃讹紝鍒濆鍊肩疆绌�
+            form.hidden = true
+          } else if (form.key === 'match') {                     // 鎼滅储鏉′欢绫诲瀷鍒囨崲鏃讹紝鍖归厤瑙勫垯绫诲瀷瀵瑰簲鍒囨崲
+            if (value === 'text') {
+              form.options = matchReg.text
+            } else if (value === 'multiselect') {
+              form.options = matchReg.multiselect
+            } else if (value === 'select' || value === 'link') {
+              form.options = matchReg.select
+            } else if (value === 'date') {
+              form.options = matchReg.date
+            } else if (value === 'datemonth') {
+              form.options = matchReg.datemonth
+            } else if (value === 'dateweek' || value === 'daterange') {
+              form.options = matchReg.daterange
+            }
+            form.hidden = true
+          }
+
+          return form
+        })
+      }, () => {
+        this.setState({
+          formlist: this.state.formlist.map(form => {
+
+            if (form.key === 'initval') {
+              form.hidden = false
+            } else if (form.key === 'match') {
+              form.initVal = form.options[0].value
+              form.hidden = false
+            }
+
+            return form
+          })
+        })
+      })
+    } else if (key === 'quick') {
+      let option = this.props.optionLibs.get(value)
+
+      this.setState({
+        formlist: this.state.formlist.map(form => {
+          if (form.key === 'options') {
+            form.initVal = option.options
+          }
+
+          return form
+        })
+      })
+    }
+  }
+
+  /**
+   * @description 鏁版嵁婧愮被鍨嬪垏鎹�
+   */
+  onChange = (e, key) => {
+    const { openType } = this.state
+    let value = e.target.value
+
+    if (key === 'resourceType') {
+      let _options = ['label', 'field', 'initval', 'type', 'match', 'resourceType', 'display', 'ratio', 'blacklist', 'required']
+
+      if (value === '0') {
+        _options = [..._options, 'options', 'quick']
+      } else if (value === '1') {
+        _options = [..._options, 'dataSource', 'valueField', 'valueText', 'orderBy', 'orderType', 'database']
+      }
+
+      if (openType === 'select' || openType === 'link') {
+        _options.push('setAll')
+      }
+      
+      if (openType === 'link') {
+        _options = [..._options, 'linkField']
+      }
+      
+      this.setState({
+        resourceType: value,
+        formlist: this.state.formlist.map(form => {
+          form.hidden = !_options.includes(form.key)
+          return form
+        })
+      })
+    }
+  }
+
+  handleSubmit = (e) => {
+    e.preventDefault()
+
+    if (this.props.inputSubmit) {
+      this.props.inputSubmit()
+    }
+  }
+
+  getFields() {
+    const { getFieldDecorator } = this.props.form
+    const fields = []
+    this.state.formlist.forEach((item, index) => {
+      if (item.hidden) return
+
+      if (item.type === 'text') { // 鏂囨湰鎼滅储
+        let rules = []
+        if (item.key === 'field') {
+          rules = [{
+            pattern: formRule.field.pattern,
+            message: formRule.field.message
+          }, {
+            max: formRule.field.max,
+            message: formRule.field.maxMessage
+          }]
+        } else {
+          rules = [{
+            max: formRule.input.max,
+            message: formRule.input.message
+          }]
+        }
+        
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" overlayClassName={item.tooltipClass} title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || '',
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  },
+                  ...rules
+                ]
+              })(<Input placeholder="" autoComplete="off" disabled={item.readonly} onPressEnter={this.handleSubmit} />)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'number') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || 6,
+                rules: [
+                  {
+                    required: item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  }
+                ]
+              })(<InputNumber min={item.min} max={item.max} precision={0} />)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'select') { // 涓嬫媺鎼滅储
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || '',
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <Select
+                  showSearch
+                  filterOption={(input, option) => option.props.children[2].toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                  onChange={(value) => {this.openTypeChange(item.key, value)}}
+                  getPopupContainer={() => document.getElementById('commontable-search-form-box')}
+                >
+                  {item.options.map(option =>
+                    <Select.Option id={option.value} title={option.text} key={option.value} value={option.value}>
+                      {item.key === 'icon' && <Icon type={option.text} />} {option.text}
+                    </Select.Option>
+                  )}
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'radio') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <Radio.Group onChange={(e) => {this.onChange(e, item.key)}}>
+                  {
+                    item.options.map(option => {
+                      return (
+                        <Radio key={option.value} value={option.value}>{option.text}</Radio>
+                      )
+                    })
+                  }
+                </Radio.Group>,
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'textarea') {
+        fields.push(
+          <Col span={20} offset={4} key={index}>
+            <Form.Item className="text-area">
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  }
+                ]
+              })(<TextArea rows={4} />)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'options') {
+        fields.push(
+          <Col span={20} offset={4} key={index}>
+            <EditTable data={item.initVal} type={this.state.openType} ref="editTable"/>
+          </Col>
+        )
+      } else if (item.type === 'multiselect') { // 澶氶��
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || []
+              })(
+                <Select
+                  showSearch
+                  mode="multiple"
+                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                >
+                  {item.options.map((option, i) =>
+                    <Select.Option id={i} key={i} value={option.value}>{option.text}</Select.Option>
+                  )}
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      }
+    })
+
+    return fields
+  }
+
+  handleConfirm = () => {
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          let isvalid = true
+          values.uuid = this.props.card.uuid
+          // 涓嬫媺鑿滃崟鎴栧叧鑱旇彍鍗�
+          if ((values.type === 'multiselect' || values.type === 'select' || values.type === 'link') && values.resourceType === '0') {
+            values.options = this.refs.editTable.state.dataSource
+            values.dataSource = ''
+            let emptys = []
+            if (values.type === 'multiselect' || values.type === 'select') {
+              emptys = values.options.filter(op => !(op.Value && op.Text))
+            } else {
+              emptys = values.options.filter(op => !(op.Value && op.Text && op.ParentID))
+            }
+            if (emptys.length > 0) {
+              isvalid = false
+            }
+          } else if ((values.type === 'multiselect' || values.type === 'select' || values.type === 'link') && values.resourceType === '1') {
+            values.options = []
+          }
+
+          if (isvalid) {
+            ['linkField', 'valueField', 'valueText', 'orderBy'].forEach(item => {
+              if (values[item]) {
+                values[item] = values[item].replace(/\s* | \t* | \v* | \r*/ig, '')
+              }
+            })
+
+            let error = Utils.verifySql(values.dataSource)
+
+            if (error) {
+              notification.warning({
+                top: 92,
+                message: '鏁版嵁婧愪腑涓嶅彲浣跨敤' + error,
+                duration: 5
+              })
+              return
+            }
+
+            resolve(values)
+          } else {
+            notification.warning({
+              top: 92,
+              message: this.props.dict['header.form.selectItem.error'],
+              duration: 5
+            })
+          }
+        } else {
+          reject(err)
+        }
+      })
+    })
+  }
+
+  render() {
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+    return (
+      <Form {...formItemLayout} className="ant-advanced-search-form commontable-search-form" id="commontable-search-form-box">
+        <Row gutter={24}>{this.getFields()}</Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(MainSearch)
\ No newline at end of file
diff --git a/src/templates/sharecomponent/searchcomponent/searchform/index.scss b/src/templates/sharecomponent/searchcomponent/searchform/index.scss
new file mode 100644
index 0000000..b027f37
--- /dev/null
+++ b/src/templates/sharecomponent/searchcomponent/searchform/index.scss
@@ -0,0 +1,24 @@
+.ant-advanced-search-form.commontable-search-form {
+  min-height: 180px;
+  .ant-col-offset-4 {
+    padding-left: 6px!important;
+    padding-bottom: 20px;
+  }
+  // .ant-form-item {
+  //   margin-bottom: 10px;
+  // }
+  .ant-form-item.text-area {
+    margin-bottom: 0px;
+    .ant-form-item-control-wrapper {
+      width: 100%;
+    }
+  }
+  .anticon-question-circle {
+    color: #c49f47;
+    position: relative;
+    left: -3px;
+  }
+  .ant-input-number {
+    width: 100%;
+  }
+}
\ No newline at end of file
diff --git a/src/templates/sharecomponent/tablecomponent/index.jsx b/src/templates/sharecomponent/tablecomponent/index.jsx
new file mode 100644
index 0000000..4a17396
--- /dev/null
+++ b/src/templates/sharecomponent/tablecomponent/index.jsx
@@ -0,0 +1,455 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { fromJS } from 'immutable'
+import { Icon, Tooltip, Select, List, notification } from 'antd'
+import moment from 'moment'
+
+import Api from '@/api'
+import Utils from '@/utils/utils.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import { queryTableSql } from '@/utils/option.js'
+
+import './index.scss'
+
+const { Option } = Select
+
+// **鎮茶鑰呭線寰�姝g‘锛屼箰瑙傝�呭線寰�鎴愬姛
+class TablesComponent extends Component {
+  static propTpyes = {
+    config: PropTypes.object,        // 瀹瑰櫒Id
+    containerId: PropTypes.string,   // 瀹瑰櫒Id
+    updatetable: PropTypes.func
+  }
+
+  state = {
+    dict: (!localStorage.getItem('lang') || localStorage.getItem('lang') === 'zh-CN') ? zhCN : enUS,
+    tables: [],          // 绯荤粺琛�
+    tableFields: [],    // 宸查�夎〃瀛楁闆�
+    selectedTables: [],  // 宸查�夎〃
+    searchlist: null,    // 鎼滅储鏉′欢闆�
+    visible: false       // 妯℃�佹鎺у埗
+  }
+
+  /**
+   * @description 鎼滅储鏉′欢鍒濆鍖�
+   */
+  UNSAFE_componentWillMount () {
+    const { config } = this.props
+
+    this.setState({
+      selectedTables: config.tables ? fromJS(config.tables).toJS() : []
+    }, () => {
+      this.gettableFields()
+    })
+  }
+
+  componentDidMount () {
+    this.gettables()
+  }
+
+  /**
+   * @description 鑾峰彇绯荤粺琛�
+   */
+  gettables = () => {
+    let param = {
+      func: 'sPC_Get_SelectedList',
+      LText: queryTableSql,
+      obj_name: 'data',
+      arr_field: 'TbName,Remark'
+    }
+
+    param.LText = Utils.formatOptions(param.LText)
+    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
+    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
+
+    Api.getSystemConfig(param).then(res => {
+      if (res.status) {
+        this.setState({
+          tables: res.data
+        })
+      } else {
+        notification.warning({
+          top: 92,
+          message: res.message,
+          duration: 5
+        })
+      }
+    })
+  }
+
+  gettableFields = () => {
+    let deffers = this.state.selectedTables.map(item => {
+      return new Promise(resolve => {
+        Api.getSystemConfig({func: 'sPC_Get_FieldName', TBName: item.TbName}).then(res => {
+          res.TBName = item.TbName
+          resolve(res)
+        })
+      })
+    })
+    Promise.all(deffers).then(response => {
+      let _columns = []
+      response.forEach(res => {
+        if (res.status) {
+          let tabmsg = {
+            tableName: res.TBName,
+            columns: res.FDName.map(item => {
+              let _type = item.FieldType.toLowerCase()
+              let _decimal = 0
+              if (/^nvarchar/.test(_type)) {
+                _type = 'text'
+              } else if (/^int/.test(_type)) {
+                _type = 'number'
+              } else if (/^decimal/.test(_type)) {
+                _decimal = _type.split(',')[1]
+                _decimal = parseInt(_decimal)
+                if (_decimal > 4) {
+                  _decimal = 4
+                }
+                _type = 'number'
+              } else if (/^decimal/.test(_type)) {
+                _decimal = _type.split(',')[1]
+                _decimal = parseInt(_decimal)
+                if (_decimal > 4) {
+                  _decimal = 4
+                }
+                _type = 'number'
+              } else if (/^datetime/.test(_type)) {
+                _type = 'datetime'
+              } else if (/^date/.test(_type)) {
+                _type = 'date'
+              } else {
+                _type = 'text'
+              }
+  
+              return {
+                field: item.FieldName,
+                label: item.FieldDec,
+                type: _type,
+                datatype: _type,
+                decimal: _decimal
+              }
+            })
+          }
+          _columns.push(tabmsg)
+        } else {
+          notification.warning({
+            top: 92,
+            message: res.message,
+            duration: 5
+          })
+        }
+      })
+
+      this.setState({
+        tableFields: _columns
+      })
+
+      this.props.updatetable(this.props.config, _columns)
+    })
+  }
+
+  queryField = (type) => {
+    const {selectedTables, tableFields, config} = this.state
+    // 鍒ゆ柇鏄惁宸查�夋嫨琛ㄥ悕
+    if (selectedTables.length === 0) {
+      notification.warning({
+        top: 92,
+        message: '璇烽�夋嫨琛ㄥ悕锛�',
+        duration: 5
+      })
+      return
+    }
+
+    // 琛ㄥ瓧娈甸泦杞负map鏁版嵁
+    let columns = new Map()
+    tableFields.forEach(table => {
+      table.columns.forEach(column => {
+        columns.set(column.field, column)
+      })
+    })
+
+    if (type === 'search') {
+      // 娣诲姞鎼滅储鏉′欢锛屽瓧娈甸泦涓瓨鍦ㄦ悳绱㈡潯浠跺瓧娈碉紝浣跨敤鎼滅储鏉′欢瀵硅薄鏇挎崲瀛楁闆嗭紝璁剧疆鏁版嵁绫诲瀷
+      config.search.forEach(item => {
+        if (columns.has(item.field)) {
+          let _datatype = columns.get(item.field).datatype
+          columns.set(item.field, {...item, selected: true, datatype: _datatype})
+        }
+      })
+    } else if (type === 'columns') {
+      // 娣诲姞鏄剧ず鍒楋紝瀛楁闆嗕腑瀛樺湪鏄剧ず鍒楀瓧娈碉紝浣跨敤鏄剧ず鍒楀璞℃浛鎹㈠瓧娈甸泦锛岃缃暟鎹被鍨�
+      config.columns.forEach(item => {
+        if (columns.has(item.field)) {
+          let _datatype = columns.get(item.field).datatype
+          columns.set(item.field, {...item, selected: true, datatype: _datatype})
+        }
+      })
+    }
+
+    // 鏄剧ず瀛楁闆嗗脊绐�
+    this.setState({
+      addType: type,
+      tableVisible: true,
+      fields: [...columns.values()]
+    })
+  }
+
+  addFieldSubmit = () => {
+    // 瀛楁闆嗕负绌猴紝鍏抽棴寮圭獥
+    if (!this.state.fields || this.state.fields.length === 0) {
+      this.setState({
+        tableVisible: false,
+        addType: ''
+      })
+    }
+
+    const {addType, config} = this.state
+
+    // 鑾峰彇宸查�夊瓧娈甸泦鍚�
+    let cards = this.refs.searchcard.state.selectCards
+    let columnsMap = new Map()
+    cards.forEach(card => {
+      columnsMap.set(card.field, card)
+    })
+
+    let items = []
+    if (addType === 'search') {
+      config.search.forEach(item => {
+        if (columnsMap.has(item.field)) {
+          let cell = columnsMap.get(item.field)
+
+          if (cell.selected && cell.type === item.type) { // 鏁版嵁鏈慨鏀�
+            items.push(item)
+          } else if (cell.selected) { // 鏁版嵁绫诲瀷淇敼
+            if (cell.type === 'select') {
+              item.match = '='
+            } else if (cell.type === 'daterange') {
+              item.match = 'between'
+            } else {
+              cell.type = 'text'
+              item.match = 'like'
+            }
+            
+            item.type = cell.type
+            item.initval = ''
+            items.push(item)
+          }
+          columnsMap.delete(item.field)
+        } else if (!item.origin) {
+          items.push(item)
+        }
+      })
+
+      let _columns = [...columnsMap.values()]
+
+      _columns.forEach(item => {
+        if (item.selected) {
+          let _match = ''
+          if (item.type === 'select') {
+            _match = '='
+          } else if (item.type === 'daterange') {
+            _match = 'between'
+          } else {
+            item.type = 'text'
+            _match = 'like'
+          }
+
+          let newcard = {
+            uuid: Utils.getuuid(),
+            label: item.label,
+            field: item.field,
+            initval: '',
+            type: item.type,
+            resourceType: '0',
+            setAll: 'false',
+            options: [],
+            dataSource: '',
+            linkField: '',
+            valueField: '',
+            valueText: '',
+            orderBy: '',
+            orderType: 'asc',
+            match: _match,
+            display: 'dropdown'
+          }
+
+          items.push(newcard)
+        }
+      })
+    } else {
+      config.columns.forEach(item => {
+        if (columnsMap.has(item.field)) {
+          let cell = columnsMap.get(item.field)
+
+          if (cell.selected) {
+            items.push(item)
+          }
+          columnsMap.delete(item.field)
+        } else if (!item.origin) {
+          items.push(item)
+        }
+      })
+
+      let _columns = [...columnsMap.values()]
+
+      _columns.forEach(item => {
+        if (item.selected) {
+          let newcard = {
+            uuid: Utils.getuuid(),
+            Align: 'left',
+            label: item.label,
+            field: item.field,
+            Hide: 'false',
+            IsSort: item.type === 'picture' ? 'false' : 'true',
+            type: item.type,
+            Width: 120
+          }
+
+          items.push(newcard)
+        }
+      })
+    }
+
+    this.setState({
+      config: {...config, [addType]: items}
+    })
+
+    notification.success({
+      top: 92,
+      message: '鎿嶄綔鎴愬姛',
+      duration: 2
+    })
+  }
+
+  onTableChange = (value) => {
+    const { config } = this.props
+    const { tables, tableFields, selectedTables } = this.state
+
+    let _table = tables.filter(item => item.TbName === value)[0]
+    let isSelected = !!selectedTables.filter(cell => cell.TbName === value)[0]
+    if (!isSelected) {
+      this.setState({
+        selectedTables: [...selectedTables, _table]
+      })
+
+      let _config = {...config, tables: [...selectedTables, _table]}
+
+      Api.getSystemConfig({func: 'sPC_Get_FieldName', TBName: value}).then(res => {
+        if (res.status) {
+          let tabmsg = {
+            tableName: _table.name,
+            columns: res.FDName.map(item => {
+              let _type = item.FieldType.toLowerCase()
+              let _decimal = 0
+              if (/^nvarchar/.test(_type)) {
+                _type = 'text'
+              } else if (/^int/.test(_type)) {
+                _type = 'number'
+              } else if (/^decimal/.test(_type)) {
+                _decimal = _type.split(',')[1]
+                _decimal = parseInt(_decimal)
+                _type = 'number'
+              } else if (/^datetime/.test(_type)) {
+                _type = 'datetime'
+              } else if (/^date/.test(_type)) {
+                _type = 'date'
+              } else {
+                _type = 'text'
+              }
+
+              return {
+                field: item.FieldName,
+                label: item.FieldDec,
+                type: _type,
+                datatype: _type,
+                decimal: _decimal
+              }
+            })
+          }
+          this.setState({
+            tableFields: [...tableFields, tabmsg]
+          })
+
+          this.props.updatetable(_config, [...tableFields, tabmsg])
+        } else {
+          notification.warning({
+            top: 92,
+            message: res.message,
+            duration: 5
+          })
+        }
+      })
+    }
+  }
+
+  deleteTable = (table) => {
+    const { config } = this.props
+    const {selectedTables, tableFields} = this.state
+
+    let _tables = selectedTables.filter(item => item.TbName !== table.TbName)
+    let _fields = tableFields.filter(item => item.tableName !== table.TbName)
+
+    this.setState({
+      selectedTables: _tables,
+      tableFields: _fields
+    })
+
+    this.props.updatetable({...config, tables: _tables}, _fields)
+  }
+
+  changeSetting = () => {
+    this.setState({
+      settingVisible: true
+    })
+  }
+
+  render() {
+    const { containerId } = this.props
+    const { dict, tables, selectedTables } = this.state
+
+    return (
+      <div className="model-table-tablemanage-view">
+        {/* 琛ㄥ悕娣诲姞 */}
+        <div className="ant-col ant-form-item-label">
+          <label>
+            <Tooltip placement="topLeft" title={dict['model.tooltip.table.guide']}>
+              <Icon type="question-circle" />
+              {dict['header.menu.table.add']}
+            </Tooltip>
+          </label>
+        </div>
+        <Select
+          showSearch
+          className="tables"
+          style={{ width: '100%' }}
+          optionFilterProp="children"
+          value={dict['header.menu.table.placeholder']}
+          onChange={this.onTableChange}
+          showArrow={false}
+          getPopupContainer={() => document.getElementById(containerId)}
+          filterOption={(input, option) => {
+            return option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0 ||
+              option.props.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
+          }}
+        > 
+          {tables.map((table, index) => (
+            <Option key={index} title={table.TbName} value={table.TbName}>{table.Remark}</Option>
+          ))}
+        </Select>
+        {selectedTables.length > 0 && <List
+          size="small"
+          bordered
+          dataSource={selectedTables}
+          renderItem={(item, index) => <List.Item key={index} title={item.Remark + ' (' + item.TbName + ')'}>
+            {item.Remark + ' (' + item.TbName + ')'}
+            <Icon type="close" onClick={() => this.deleteTable(item)}/>
+            <div className="bottom-mask"></div>
+          </List.Item>}
+        />}
+      </div>
+    )
+  }
+}
+
+export default TablesComponent
\ No newline at end of file
diff --git a/src/templates/sharecomponent/tablecomponent/index.scss b/src/templates/sharecomponent/tablecomponent/index.scss
new file mode 100644
index 0000000..aa254b7
--- /dev/null
+++ b/src/templates/sharecomponent/tablecomponent/index.scss
@@ -0,0 +1,7 @@
+.model-table-tablemanage-view {
+  .tables {
+    .ant-select-selection-selected-value {
+      opacity: 0.4!important;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/templates/subtableconfig/index.jsx b/src/templates/subtableconfig/index.jsx
index dab3aa9..2b7b9df 100644
--- a/src/templates/subtableconfig/index.jsx
+++ b/src/templates/subtableconfig/index.jsx
@@ -4,39 +4,32 @@
 import { is, fromJS } from 'immutable'
 import { DndProvider } from 'react-dnd'
 import HTML5Backend from 'react-dnd-html5-backend'
-import { Button, Card, Modal, Collapse, notification, Spin, Select, List, Icon, Empty, Switch, Tooltip, message } from 'antd'
+import { Button, Card, Modal, Collapse, notification, Spin, Icon, Switch, Tooltip, Col } from 'antd'
 import moment from 'moment'
 
 import Api from '@/api'
-import options from '@/store/options.js'
-import zhCN from '@/locales/zh-CN/comtable.js'
-import enUS from '@/locales/en-US/comtable.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
 import Utils from '@/utils/utils.js'
-import { getSearchForm, getActionForm, getColumnForm } from '@/templates/zshare/formconfig'
-import { queryTableSql } from '@/utils/option.js'
 
-import ActionForm from './actionform'
+import TableComponent from '@/templates/sharecomponent/tablecomponent'
+import FieldsComponent from '@/templates/sharecomponent/fieldscomponent'
+import ChartGroupComponent from '@/templates/sharecomponent/chartgroupcomponent'
+import SearchComponent from '@/templates/sharecomponent/searchcomponent'
+import ActionComponent from '@/templates/sharecomponent/actioncomponent'
+import ColumnComponent from '@/templates/sharecomponent/columncomponent'
+
 import SettingForm from './settingform'
-import SearchForm from '@/templates/zshare/searchform'
-import ColumnForm from '@/templates/zshare/columnform'
-import DragElement from '@/templates/zshare/dragelement'
-import ColspanForm from '@/templates/zshare/colspanform'
-import GridBtnForm from '@/templates/zshare/gridbtnform'
-import EditCard from '@/templates/zshare/editcard'
-import VerifyCard from '@/templates/zshare/verifycard'
-import VerifyCardPrint from '@/templates/zshare/verifycardprint'
-import VerifyCardExcelIn from '@/templates/zshare/verifycardexcelin'
-import VerifyCardExcelOut from '@/templates/zshare/verifycardexcelout'
 import MenuForm from '@/templates/zshare/menuform'
 import EditComponent from '@/templates/zshare/editcomponent'
 import SourceElement from '@/templates/zshare/dragelement/source'
 import CreateFunc from '@/templates/zshare/createfunc'
 import CreateInterface from '@/templates/zshare/createinterface'
+import ChartComponent from '@/templates/zshare/chartcomponent'
 import Source from './source'
 import './index.scss'
 
 const { Panel } = Collapse
-const { Option } = Select
 const { confirm } = Modal
 const CommonDict = (!localStorage.getItem('lang') || localStorage.getItem('lang') === 'zh-CN') ? zhCN : enUS
 
@@ -57,15 +50,11 @@
     dict: CommonDict,        // 瀛楀吀
     config: null,            // 椤甸潰閰嶇疆
     visible: false,          // 鎼滅储鏉′欢銆佹寜閽�佹樉绀哄垪锛屾ā鎬佹鏄剧ず鎺у埗
-    modalTitle: '',          // 妯℃�佹鐨勬爣棰�
-    tableVisible: false,     // 鏁版嵁琛ㄥ瓧娈垫ā鎬佹
-    addType: '',             // 娣诲姞绫诲瀷-鎼滅储鏉′欢鎴栨樉绀哄垪
-    tableColumns: [],        // 琛ㄦ牸鏄剧ず鍒�
+    tableFields: [],         // 宸查�夎〃瀛楁闆�
     fields: null,            // 鎼滅储鏉′欢鍙婃樉绀哄垪锛屽彲閫夊瓧娈�
     menuformlist: null,      // 鍩烘湰淇℃伅琛ㄥ崟瀛楁
     formlist: null,          // 鎼滅储鏉′欢銆佹寜閽�佹樉绀哄垪琛ㄥ崟瀛楁
     formtemp: '',            // 琛ㄥ崟绫诲瀷锛屾樉绀哄垪銆佹寜閽�佹悳绱㈡潯浠�
-    modaltype: '',           // 妯℃�佹绫诲瀷锛屾帶鍒舵ā鎬佹鏄剧ず
     card: null,              // 缂栬緫鍏冪礌
     menuloading: false,      // 鑿滃崟淇濆瓨涓�
     menucloseloading: false, // 鑿滃崟鍏抽棴鏃讹紝閫夋嫨淇濆瓨
@@ -78,13 +67,14 @@
     originActions: null,     // 鍘熷鎸夐挳淇℃伅锛屼娇鐢ㄥ凡鏈夌敤鎴锋ā鏉�
     delActions: [],          // 鍒犻櫎鎸夐挳鍒楄〃
     copyActions: [],         // 澶嶅埗鎸夐挳缁�
-    showColumnName: false,   // 鏄剧ず鍒楀瓧娈靛悕鎺у埗
     tabviews: [],            // 鎵�鏈夋爣绛鹃〉
     profileVisible: false,   // 楠岃瘉淇℃伅妯℃�佹
     optionLibs: null,        // 鑷畾涔変笅鎷夐�夐」搴�
     thawButtons: [],         // 宸查�夋嫨瑕佽В鍐荤殑鎸夐挳
     activeKey: '0',          // 榛樿灞曞紑鍩烘湰淇℃伅
-    sqlVerifing: false       // sql楠岃瘉
+    sqlVerifing: false,      // sql楠岃瘉
+    chartview: null,         // 褰撳墠瑙嗗浘
+    pasteContent: null       // 绮樿创鍐呭
   }
 
   /**
@@ -142,7 +132,22 @@
 
     let _activeKey =  editSubTab ? editSubTab.activeKey : editTab.activeKey
 
+    // 鍏煎
+    if (!_config.charts) {
+      _config.expand = false
+      _config.charts = [{
+        uuid: Utils.getuuid(),
+        label: '',
+        title: '',
+        chartType: 'table',
+        icon: 'table',
+        Hide: 'false',
+        blacklist: []
+      }]
+    }
+
     this.setState({
+      chartview: _config.charts[0].uuid,
       originActions: _oriActions,
       optionLibs: optionLibs,
       config: _config,
@@ -184,148 +189,46 @@
    * 2銆佹牴鎹厤缃俊鎭腑宸蹭娇鐢ㄨ〃鑾峰彇鐩稿叧瀛楁淇℃伅
    */
   componentDidMount () {
-    let param = {
-      func: 'sPC_Get_SelectedList',
-      LText: queryTableSql,
-      obj_name: 'data',
-      arr_field: 'TbName,Remark'
-    }
-
-    param.LText = Utils.formatOptions(param.LText)
-    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
-    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
-
-    Api.getSystemConfig(param).then(res => {
-      if (res.status) {
-        this.setState({
-          tables: res.data
-        })
-      } else {
-        notification.warning({
-          top: 92,
-          message: res.message,
-          duration: 5
-        })
-      }
-    })
-
-    let deffers = this.state.selectedTables.map(item => {
-      return new Promise(resolve => {
-        Api.getSystemConfig({func: 'sPC_Get_FieldName', TBName: item.TbName}).then(res => {
-          res.TBName = item.TbName
-          resolve(res)
-        })
-      })
-    })
-    Promise.all(deffers).then(response => {
-      let _columns = []
-      response.forEach(res => {
-        if (res.status) {
-          let tabmsg = {
-            tableName: res.TBName,
-            columns: res.FDName.map(item => {
-              let _type = item.FieldType.toLowerCase()
-              let _decimal = 0
-              if (/^nvarchar/.test(_type)) {
-                _type = 'text'
-              } else if (/^int/.test(_type)) {
-                _type = 'number'
-              } else if (/^decimal/.test(_type)) {
-                _decimal = _type.split(',')[1]
-                _decimal = parseInt(_decimal)
-                if (_decimal > 4) {
-                  _decimal = 4
-                }
-                _type = 'number'
-              } else if (/^decimal/.test(_type)) {
-                _decimal = _type.split(',')[1]
-                _decimal = parseInt(_decimal)
-                if (_decimal > 4) {
-                  _decimal = 4
-                }
-                _type = 'number'
-              } else if (/^datetime/.test(_type)) {
-                _type = 'datetime'
-              } else if (/^date/.test(_type)) {
-                _type = 'date'
-              } else {
-                _type = 'text'
-              }
-  
-              return {
-                field: item.FieldName,
-                label: item.FieldDec,
-                type: _type,
-                datatype: _type,
-                decimal: _decimal
-              }
-            })
-          }
-          _columns.push(tabmsg)
-        } else {
-          notification.warning({
-            top: 92,
-            message: res.message,
-            duration: 5
-          })
-        }
-      })
-
-      this.setState({
-        tableColumns: _columns
-      })
-    })
-
-    Api.getSystemConfig({func: 'sPC_Get_UserTemp', TypeCharTwo: 'tab'}).then(res => {
-      if (res.status) {
-        this.setState({
-          tabviews: res.UserTemp.map(temp => {
-            return {
-              uuid: temp.MenuID,
-              value: temp.MenuID,
-              text: temp.MenuName,
-              type: temp.Template,
-              MenuNo: temp.MenuNo
-            }
-          })
-        })
-      } else {
-        notification.warning({
-          top: 92,
-          message: res.message,
-          duration: 5
-        })
-      }
-    })
+    this.reloadTab(false)
   }
 
   /**
    * @description 鍔犺浇鎴栧埛鏂版爣绛句俊鎭�
    */
-  reloadTab = () => {
+  reloadTab = (type) => {
     this.setState({
-      loading: true,
+      loading: type,
       tabviews: []
     })
     Api.getSystemConfig({func: 'sPC_Get_UserTemp', TypeCharTwo: 'tab'}).then(res => {
       if (res.status) {
+        let _tabviews = []
+        res.UserTemp.forEach(temp => {
+          let item = {
+            uuid: temp.MenuID,
+            value: temp.MenuID,
+            text: temp.MenuName,
+            type: temp.Template,
+            MenuNo: temp.MenuNo
+          }
+
+          if (this.props.config && temp.MenuID === this.props.config.uuid) return
+
+          _tabviews.push(item)
+        })
+
         this.setState({
           loading: false,
-          tabviews: res.UserTemp.map(temp => {
-            return {
-              uuid: temp.MenuID,
-              value: temp.MenuID,
-              text: temp.MenuName,
-              type: temp.Template,
-              MenuNo: temp.MenuNo
-            }
+          tabviews: _tabviews
+        })
+
+        if (type) {
+          notification.success({
+            top: 92,
+            message: '鍒锋柊鎴愬姛銆�',
+            duration: 2
           })
-        })
-        notification.success({
-          top: 92,
-          message: '鍒锋柊鎴愬姛銆�',
-          duration: 2
-        })
+        }
       } else {
         this.setState({
           loading: false
@@ -392,583 +295,6 @@
   }
 
   /**
-   * @description 鍏冪礌娣诲姞鎴栨嫋鍔ㄦ椂椤哄簭鍙樺寲
-   */
-  handleList = (type, list, card) => {
-    const { config } = this.state
-
-    if (list.length > config[type].length) {
-      list = list.filter(item => !item.origin)
-
-      if (type === 'search') {
-        this.handleSearch(card)
-      } else if (type === 'action') {
-        this.handleAction(card)
-      } else if (type === 'columns') {
-        this.handleColumn(card)
-      }
-    }
-
-    this.setState({config: {...config, [type]: list}})
-  }
-
-  /**
-   * @description 鎼滅储鏉′欢缂栬緫锛岃幏鍙栨悳绱㈡潯浠惰〃鍗曚俊鎭�
-   */
-  handleSearch = (card) => {
-    this.setState({
-      modaltype: 'search',
-      card: card,
-      formlist: getSearchForm(card, this.props.sysRoles)
-    })
-  }
-
-  /**
-   * @description 鎸夐挳缂栬緫锛岃幏鍙栨寜閽〃鍗曚俊鎭�
-   */
-  handleAction = (card, type) => {
-    let ableField = this.props.permFuncField.join(', ')
-    let functip = <div>
-      <p style={{marginBottom: '5px'}}>{this.state.dict['header.modal.func.innerface'].replace('@ableField', ableField)}</p>
-      <p>{this.state.dict['header.modal.func.outface']}</p>
-    </div>
-
-    this.setState({
-      modaltype: type === 'copy' ? 'actionCopy' : 'actionEdit',
-      card: card,
-      formlist: getActionForm(card, functip, this.state.config, this.props.permFuncField)
-    })
-  }
-
-  /**
-   * @description 鏄剧ず鍒椾笌鍚堝苟鍒楃紪杈戯紝鑾峰彇琛ㄥ崟淇℃伅
-   */
-  handleColumn = (card) => {
-    const { menu } = this.props
-
-    if (card.type !== 'colspan') {
-      let menulist = menu.fstMenuList.map(item => {
-        return {
-          value: item.MenuID,
-          label: item.text,
-          isLeaf: false
-        }
-      })
-
-      if ((card.type === 'text' || card.type === 'number') && card.linkmenu && card.linkmenu.length > 0) {
-        let _param = {
-          func: 'sPC_Get_FunMenu',
-          ParentID: card.linkmenu[0],
-          systemType: options.systemType,
-          debug: 'Y'
-        }
-
-        this.setState({
-          loading: true
-        })
-    
-        Api.getSystemConfig(_param).then(result => {
-          if (result.status) {
-            menulist = menulist.map(item => {
-              if (item.value === card.linkmenu[0]) {
-                item.children = result.data.map(item => {
-                  let submenu = {
-                    value: item.ParentID,
-                    label: item.MenuNameP,
-                    children: item.FunMenu.map(cell => {
-                      return {
-                        value: cell.MenuID,
-                        label: cell.MenuName,
-                        MenuID: cell.MenuID,
-                        MenuName: cell.MenuName,
-                        MenuNo: cell.MenuNo,
-                        Ot: cell.Ot,
-                        PageParam: cell.PageParam,
-                        LinkUrl: cell.LinkUrl,
-                        disabled: cell.MenuID === menu.MenuID
-                      }
-                    })
-                  }
-
-                  return submenu
-                })
-              }
-              return item
-            })
-          } else {
-            notification.warning({
-              top: 92,
-              message: result.message,
-              duration: 5
-            })
-          }
-
-          this.setState({
-            loading: false,
-            modaltype: 'columns',
-            card: card,
-            formlist: getColumnForm(card, this.props.sysRoles, menulist)
-          })
-        })
-      } else {
-        this.setState({
-          modaltype: 'columns',
-          card: card,
-          formlist: getColumnForm(card, this.props.sysRoles, menulist)
-        })
-      }
-    } else {
-      this.setState({
-        modaltype: 'colspan',
-        card: card
-      })
-    }
-  }
-
-  /**
-   * @description 鎿嶄綔鍒楃紪杈�
-   */
-  handleGridBtn = () => {
-    this.setState({
-      modaltype: 'gridbtn'
-    })
-  }
-
-  /**
-   * @description 鎼滅储銆佹寜閽�佹樉绀哄垪淇敼鍚庢彁浜や繚瀛�
-   * 1銆佹悳绱㈡潯浠朵繚瀛橈紝褰撶被鍨嬩负涓嬫媺妗嗕笖瀛樺湪鏁版嵁婧愭椂锛屽皢鏌ヨ鏉′欢鎷兼帴涓簊ql锛屽苟鐢╞ase64杞爜
-   * 2銆佹寜閽寘鎷甯哥紪杈戝拰澶嶅埗锛屽鍒舵椂,鎸夐挳鍒楁湯灏炬坊鍔�
-   * 3銆佹坊鍔犳垨缂栬緫鍒楋紝淇濆瓨鏃讹紝濡傛寜閽綅缃缃负琛ㄦ牸锛屽垯淇敼鎿嶄綔鍒楁樉绀虹姸鎬�
-   */
-  handleSubmit = () => {
-    const { card, config, modaltype, optionLibs } = this.state
-
-    if (modaltype === 'search') {
-      this.searchFormRef.handleConfirm().then(res => {
-        if ( // 鏇存柊涓嬫媺瀛楀吀
-          (res.type === 'select' || res.type === 'multiselect' || res.type === 'link') &&
-          res.resourceType === '0' &&
-          res.options && res.options.length > 0
-        ) {
-          optionLibs.set(config.uuid + res.uuid, {
-            uuid: config.uuid + res.uuid,
-            label: res.label,
-            parname: config.tabName,
-            type: 'search',
-            options: res.options
-          })
-        }
-
-        let fieldrepet = false // 瀛楁閲嶅
-        let labelrepet = false // 鎻愮ず鏂囧瓧閲嶅
-
-        let _search = config.search.map(item => {
-          if (item.uuid !== res.uuid && res.field && item.field) {
-            if (item.field === res.field) {
-              fieldrepet = true
-            } else if (item.label === res.label) {
-              labelrepet = true
-            }
-          }
-
-          if (item.uuid === res.uuid) {
-            return res
-          } else {
-            return item
-          }
-        })
-
-        if (fieldrepet) {
-          notification.warning({
-            top: 92,
-            message: '瀛楁宸插瓨鍦紒',
-            duration: 5
-          })
-          return
-        } else if (labelrepet) {
-          notification.warning({
-            top: 92,
-            message: '鍚嶇О宸插瓨鍦紒',
-            duration: 5
-          })
-          return
-        }
-
-        _search = _search.filter(item => !item.origin)
-
-        if ((res.type === 'select' || res.type === 'multiselect' || res.type === 'link') && res.resourceType === '1' && /\s/.test(res.dataSource)) {
-          this.setState({
-            sqlVerifing: true
-          })
-  
-          let param = {
-            func: 's_debug_sql',
-            LText: res.dataSource
-          }
-          param.LText = Utils.formatOptions(param.LText)
-          param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
-          param.secretkey = Utils.encrypt(param.LText, param.timestamp)
-  
-          if (window.GLOB.mainSystemApi && res.database === 'sso') {
-            param.rduri = window.GLOB.mainSystemApi
-          }
-          
-          Api.getLocalConfig(param).then(result => {
-            if (result.status) {
-              this.setState({
-                sqlVerifing: false,
-                config: {...config, search: _search},
-                optionLibs: optionLibs,
-                modaltype: ''
-              })
-            } else {
-              this.setState({sqlVerifing: false})
-              
-              Modal.error({
-                title: result.message
-              })
-            }
-          })
-        } else {
-          this.setState({
-            config: {...config, search: _search},
-            optionLibs: optionLibs,
-            modaltype: ''
-          })
-        }
-      })
-    } else if (modaltype === 'actionEdit' || modaltype === 'actionCopy') {
-      this.actionFormRef.handleConfirm().then(res => {
-        let _action = config.action.map(item => {
-          if (item.uuid === res.uuid) {
-            return res
-          } else {
-            return item
-          }
-        })
-        _action = _action.filter(item => !item.origin)
-
-        if (modaltype === 'actionCopy') {
-          _action.push(res)
-        }
-
-        // 澶嶅埗鎸夐挳鍓嶅悗鐨嗕负琛ㄥ崟鏃讹紝澶嶅埗琛ㄥ崟閰嶇疆淇℃伅锛宨d瀛樹簬澶嶅埗鍒楄〃
-        if (res.OpenType === 'pop' && card.originCard && card.originCard.OpenType === 'pop') {
-          Api.getSystemConfig({
-            func: 'sPC_Get_LongParam',
-            MenuID: card.originCard.uuid
-          }).then(result => {
-            if (result.status && result.LongParam) {
-              let _LongParam = ''
-
-              // 瑙f瀽閰嶇疆锛屼慨鏀规ā鎬佹鏍囬鍚嶇О
-              if (result.LongParam) {
-                try {
-                  _LongParam = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam)))
-                } catch (e) {
-                  console.warn('Parse Failure')
-                  _LongParam = ''
-                }
-              }
-              if (_LongParam && _LongParam.type === 'Modal') {
-                try {
-                  _LongParam.setting.title = res.label
-                  _LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(_LongParam)))
-                } catch {
-                  console.warn('Stringify Failure')
-                  _LongParam = ''
-                }
-              } else {
-                _LongParam = ''
-              }
-
-              let param = {
-                func: 'sPC_ButtonParam_AddUpt',
-                ParentID: config.uuid,
-                MenuID: res.uuid,
-                MenuNo: config.tabNo,
-                Template: 'Modal',
-                MenuName: res.label,
-                PageParam: JSON.stringify({Template: 'Modal'}),
-                LongParam: _LongParam
-              }
-              Api.getSystemConfig(param).then(response => {
-                if (!response.status) {
-                  notification.warning({
-                    top: 92,
-                    message: response.message,
-                    duration: 5
-                  })
-                } else {
-                  this.setState({
-                    copyActions: [...this.state.copyActions, res.uuid]
-                  })
-                }
-              })
-            }
-          })
-        }
-
-        // 鍒ゆ柇鏄惁瀛樺湪鎿嶄綔鍒�
-        let _hasGridbtn = _action.filter(act => act.position === 'grid').length > 0
-        let _gridBtn = config.gridBtn
-
-        if (_gridBtn) {
-          _gridBtn.display = _hasGridbtn
-        } else {
-          _gridBtn = {
-            display: _hasGridbtn,
-            Align: 'center',
-            IsSort: 'false',
-            uuid: Utils.getuuid(),
-            label: this.state.dict['header.form.column.action'],
-            type: 'action',
-            style: 'button',
-            show: 'horizontal',
-            Width: 120
-          }
-        }
-
-        this.setState({
-          config: {...config, action: _action, gridBtn: _gridBtn},
-          modaltype: ''
-        })
-      })
-    } else if (modaltype === 'columns' || modaltype === 'colspan') {
-      this.columnFormRef.handleConfirm().then(res => {
-        let fieldrepet = false // 瀛楁閲嶅
-        let labelrepet = false // 鎻愮ず鏂囧瓧閲嶅
-
-        let _columns = config.columns.map(item => {
-          if (item.uuid !== res.uuid && res.field && item.field) {
-            if (item.field === res.field) {
-              fieldrepet = true
-            } else if (item.label === res.label) {
-              labelrepet = true
-            }
-          }
-
-          if (item.uuid === res.uuid) {
-            return res
-          } else {
-            return item
-          }
-        })
-
-        if (fieldrepet) {
-          notification.warning({
-            top: 92,
-            message: '瀛楁宸插瓨鍦紒',
-            duration: 5
-          })
-          return
-        } else if (labelrepet) {
-          notification.warning({
-            top: 92,
-            message: '鍚嶇О宸插瓨鍦紒',
-            duration: 5
-          })
-          return
-        }
-
-        _columns = _columns.filter(item => !item.origin)
-
-        this.setState({
-          config: {...config, columns: _columns},
-          modaltype: ''
-        })
-      })
-    } else if (modaltype === 'gridbtn') {
-      this.gridBtnFormRef.handleConfirm().then(res => {
-        this.setState({
-          config: {...config, gridBtn: res},
-          modaltype: ''
-        })
-      })
-    }
-  }
-
-  /**
-   * @description 鍙栨秷淇濆瓨锛屽鏋滃厓绱犱负鏂版坊鍏冪礌锛屽垯浠庡簭鍒椾腑鍒犻櫎
-   */
-  editModalCancel = () => {
-    const { config, card, modaltype } = this.state
-
-    if (card.focus) {
-      let _config = null
-      if (modaltype === 'search') {
-        let _search = config.search.filter(item => item.uuid !== card.uuid)
-        _config = {...config, search: _search}
-      } else if (modaltype === 'actionEdit') {
-        let _action = config.action.filter(item => item.uuid !== card.uuid)
-        _config = {...config, action: _action}
-      } else if (modaltype === 'columns' || modaltype === 'colspan') {
-        let _columns = config.columns.filter(item => item.uuid !== card.uuid)
-        _config = {...config, columns: _columns}
-      } else {
-        _config = config
-      }
-
-      this.setState({
-        card: null,
-        config: _config,
-        modaltype: ''
-      })
-    } else {
-      this.setState({
-        card: null,
-        modaltype: ''
-      })
-    }
-  }
-
-  /**
-   * @description 鍒涘缓鎸夐挳瀛樺偍杩囩▼
-   */
-  creatFunc = () => {
-    let _config = JSON.parse(JSON.stringify(this.state.config))
-
-    this.actionFormRef.handleConfirm().then(res => {
-      let btn = res         // 鎸夐挳淇℃伅
-      let newLText = ''     // 鍒涘缓瀛樺偍杩囩▼sql
-      let DelText = ''      // 鍒犻櫎瀛樺偍杩囩▼sql
-
-      // 鍒涘缓瀛樺偍杩囩▼锛屽繀椤诲~鍐欏唴閮ㄥ嚱鏁板悕
-      if (!btn.innerFunc) {
-        notification.warning({
-          top: 92,
-          message: '璇峰~鍐欏唴閮ㄥ嚱鏁帮紒',
-          duration: 5
-        })
-        return
-      }
-
-      new Promise(resolve => {
-        // 寮圭獥锛堣〃鍗曪級绫绘寜閽紝鍏堣幏鍙栨寜閽厤缃俊鎭紝濡傛灉灏氭湭閰嶇疆鎸夐挳鍒欎細鎶ラ敊骞剁粓姝€��
-        // 鑾峰彇淇℃伅鍚庣敓鎴愬垹闄ゅ拰鍒涘缓瀛樺偍杩囩▼鐨勮鍙�
-        if (btn.OpenType === 'pop') {
-          Api.getSystemConfig({
-            func: 'sPC_Get_LongParam',
-            MenuID: btn.uuid
-          }).then(res => {
-            let _LongParam = ''
-            if (res.status && res.LongParam) {
-              try {
-                _LongParam = JSON.parse(window.decodeURIComponent(window.atob(res.LongParam)))
-              } catch (e) {
-                console.warn('Parse Failure')
-                _LongParam = ''
-              }
-            }
-
-            if (_LongParam) {
-              let fields = []
-              if (_LongParam.groups.length > 0) {
-                _LongParam.groups.forEach(group => {
-                  fields = [...fields, ...group.sublist]
-                })
-              } else {
-                fields = _LongParam.fields
-              }
-
-              let _param = {
-                funcName: btn.innerFunc,
-                name: _config.setting.tableName || '',
-                fields: fields,
-                menuNo: _config.tabNo
-              }
-              newLText = Utils.formatOptions(Utils.getfunc(_param, btn, {MenuID: _config.uuid, MenuName: _config.tabName}, _config))
-              DelText = Utils.formatOptions(Utils.dropfunc(_param.funcName))
-              resolve(true)
-            } else {
-              notification.warning({
-                top: 92,
-                message: '寮圭獥锛堣〃鍗曪級鎸夐挳锛岃鍏堥厤缃〃鍗曚俊鎭紒',
-                duration: 5
-              })
-              resolve(false)
-            }
-          })
-        } else if (btn.OpenType === 'excelIn') {
-          if (btn.verify && btn.verify.sheet && btn.verify.columns && btn.verify.columns.length > 0) {
-            let _param = {
-              funcName: btn.innerFunc,
-              menuNo: _config.tabNo
-            }
-            newLText = Utils.formatOptions(Utils.getexcelInfunc(_param, btn, {MenuID: _config.uuid, MenuName: _config.tabName}))
-            DelText = Utils.formatOptions(Utils.dropfunc(_param.funcName))
-            resolve(true)
-          } else {
-            notification.warning({
-              top: 92,
-              message: '璇峰畬鍠勫鍏xcel楠岃瘉淇℃伅锛�',
-              duration: 5
-            })
-            resolve(false)
-          }
-        } else if (btn.OpenType === 'excelOut') {
-          let _param = {
-            innerFunc: btn.innerFunc
-          }
-
-          newLText = Utils.formatOptions(Utils.getTableFunc(_param, {MenuID: _config.uuid, MenuName: _config.tabName, MenuNo: _config.tabNo}, _config)) // 鍒涘缓瀛樺偍杩囩▼sql
-          DelText = Utils.formatOptions(Utils.dropfunc(btn.innerFunc))
-
-          resolve(true)
-        } else {
-          let _param = {
-            funcName: btn.innerFunc,
-            name: _config.setting.tableName || '',
-            fields: '',
-            menuNo: _config.tabNo
-          }
-          newLText = Utils.formatOptions(Utils.getfunc(_param, btn, {MenuID: _config.uuid, MenuName: _config.tabName}, _config))
-          DelText = Utils.formatOptions(Utils.dropfunc(_param.funcName))
-          resolve(true)
-        }
-      }).then(res => {
-        if (!res) return
-
-        this.refs.btnCreatFunc.exec(btn.innerFunc, newLText, DelText).then(result => {
-          if (result !== 'success') return
-
-          _config.action = _config.action.map(item => {
-            if (item.uuid === btn.uuid) {
-              return btn
-            } else {
-              return item
-            }
-          })
-          _config.action = _config.action.filter(item => !item.origin)
-
-          // 鍒ゆ柇鏄惁瀛樺湪鎿嶄綔鍒�
-          let _hasGridbtn = _config.action.filter(act => act.position === 'grid').length > 0
-
-          if (_config.gridBtn) {
-            _config.gridBtn.display = _hasGridbtn
-          } else {
-            _config.gridBtn = {
-              display: _hasGridbtn,
-              Align: 'center',
-              IsSort: 'false',
-              uuid: Utils.getuuid(),
-              label: this.state.dict['header.form.column.action'],
-              type: 'action',
-              style: 'button',
-              show: 'horizontal',
-              Width: 120
-            }
-          }
-  
-          this.setState({
-            config: _config,
-          })
-        })
-      })
-    })
-  }
-
-  /**
    * @description 鍒涘缓琛ㄦ牸瀛樺偍杩囩▼
    */
   tableCreatFunc = () => {
@@ -999,90 +325,6 @@
     })
   }
 
-  deleteElement = (element) => {
-    const { thawButtons } = this.state
-
-    let _this = this
-    confirm({
-      content: `纭畾鍒犻櫎<<${element.card.label}>>鍚楋紵`,
-      okText: this.state.dict['header.confirm'],
-      cancelText: this.state.dict['header.cancel'],
-      onOk() {
-        let _config = JSON.parse(JSON.stringify(_this.state.config))
-        _config[element.type] = _config[element.type].filter(item => {
-          if (item.uuid === element.card.uuid) {
-            return false
-          } else {
-            return true
-          }
-        })
-
-        // 鍒犻櫎鎸夐挳鍏冪礌
-        let _delActions = _this.state.delActions
-        if (element.type === 'action') {
-          _delActions.push(element)
-        }
-
-        _this.setState({
-          config: _config,
-          delActions: _delActions,
-          thawButtons: thawButtons.filter(key => key !== element.card.uuid)
-        })
-      },
-      onCancel() {}
-    })
-  }
-
-  /**
-   * @description 楠岃瘉淇℃伅閰嶇疆
-   */
-  profileAction = (element) => {
-    this.setState({
-      profileVisible: true,
-      card: element
-    })
-  }
-
-  /**
-   * @description 鎸夐挳鍙屽嚮瑙﹀彂瀛愰厤缃�
-   */
-  btnDoubleClick = (element) => {
-    if (!element.origin && (element.OpenType === 'pop' || element.OpenType === 'popview' || element.OpenType === 'blank' || element.OpenType === 'tab')) {
-      this.setSubConfig(element)
-    } else {
-      notification.warning({
-        top: 92,
-        message: '姝ゆ寜閽棤瀛愰厤缃」锛�',
-        duration: 5
-      })
-    }
-  }
-
-  /**
-   * @description 楠岃瘉淇℃伅淇濆瓨
-   */
-  verifySubmit = () => {
-    const { card } = this.state
-    let config = JSON.parse(JSON.stringify(this.state.config))
-    
-    this.verifyRef.handleConfirm().then(res => {
-      
-      config.action = config.action.map(item => {
-        if (item.uuid === card.uuid) {
-          item.verify = res
-        }
-  
-        return item
-      })
-  
-      this.setState({
-        profileVisible: false,
-        config: config,
-        card: ''
-      })
-    })
-  }
-
   /**
    * @description 鏍囩椤典繚瀛�
    */
@@ -1102,17 +344,6 @@
         if (config.columns[0] && config.columns[0].origin) {
           config.columns = config.columns.filter(item => !item.origin)
         }
-      }
-
-      let btnNames = config.action.map(item => item.label)
-      btnNames = Array.from(new Set(btnNames))
-      if (btnNames.length < config.action.length) {
-        notification.warning({
-          top: 92,
-          message: '鎸夐挳鍚嶇О涓嶅彲鐩稿悓锛�',
-          duration: 5
-        })
-        return
       }
 
       let _LongParam = ''
@@ -1563,7 +794,7 @@
     if (originConfig.isAdd) {
       confirm({
         content: '鑿滃崟灏氭湭鎻愪氦锛岀‘瀹氭斁寮冧繚瀛樺悧锛�',
-        okText: this.state.dict['header.confirm'],
+        okText: this.state.dict['model.confirm'],
         cancelText: this.state.dict['header.cancel'],
         onOk() {
           _this.handleViewBack()
@@ -1587,265 +818,6 @@
         })
       })
     }
-  }
-
-  queryField = (type) => {
-    const {selectedTables, tableColumns, config} = this.state
-    // 鍒ゆ柇鏄惁宸查�夋嫨琛ㄥ悕
-    if (selectedTables.length === 0) {
-      notification.warning({
-        top: 92,
-        message: '璇烽�夋嫨琛ㄥ悕锛�',
-        duration: 5
-      })
-      return
-    }
-
-    // 琛ㄥ瓧娈甸泦杞负map鏁版嵁
-    let columns = new Map()
-    tableColumns.forEach(table => {
-      table.columns.forEach(column => {
-        columns.set(column.field, column)
-      })
-    })
-
-    if (type === 'search') {
-      // 娣诲姞鎼滅储鏉′欢锛屽瓧娈甸泦涓瓨鍦ㄦ悳绱㈡潯浠跺瓧娈碉紝浣跨敤鎼滅储鏉′欢瀵硅薄鏇挎崲瀛楁闆嗭紝璁剧疆鏁版嵁绫诲瀷
-      config.search.forEach(item => {
-        if (columns.has(item.field)) {
-          let _datatype = columns.get(item.field).datatype
-          columns.set(item.field, {...item, selected: true, datatype: _datatype})
-        }
-      })
-    } else if (type === 'columns') {
-      // 娣诲姞鏄剧ず鍒楋紝瀛楁闆嗕腑瀛樺湪鏄剧ず鍒楀瓧娈碉紝浣跨敤鏄剧ず鍒楀璞℃浛鎹㈠瓧娈甸泦锛岃缃暟鎹被鍨�
-      config.columns.forEach(item => {
-        if (columns.has(item.field)) {
-          let _datatype = columns.get(item.field).datatype
-          columns.set(item.field, {...item, selected: true, datatype: _datatype})
-        }
-      })
-    }
-
-    // 鏄剧ず瀛楁闆嗗脊绐�
-    this.setState({
-      addType: type,
-      tableVisible: true,
-      fields: [...columns.values()]
-    })
-  }
-
-  addFieldSubmit = () => {
-    // 瀛楁闆嗕负绌猴紝鍏抽棴寮圭獥
-    if (!this.state.fields || this.state.fields.length === 0) {
-      this.setState({
-        tableVisible: false,
-        addType: ''
-      })
-    }
-
-    const {addType, config} = this.state
-    const textmatch = { // 閫夋嫨text鏃跺尮閰嶈鍒�
-      text: 'like',
-      number: 'like',
-      datetime: 'like',
-      date: 'like'
-    }
-    const selectmatch = { // 閫夋嫨select鏃跺尮閰嶈鍒�
-      text: '=',
-      number: '=',
-      datetime: '=',
-      date: '='
-    }
-    const datematch = { // 閫夋嫨dateRange鏃跺尮閰嶈鍒�
-      text: 'between',
-      number: 'between',
-      datetime: 'between',
-      date: 'between'
-    }
-
-    // 鑾峰彇宸查�夊瓧娈甸泦鍚�
-    let cards = this.refs.searchcard.state.selectCards
-    let columnsMap = new Map()
-    cards.forEach(card => {
-      columnsMap.set(card.field, card)
-    })
-
-    let items = []
-    if (addType === 'search') {
-      config.search.forEach(item => {
-        if (columnsMap.has(item.field)) {
-          let cell = columnsMap.get(item.field)
-
-          if (cell.selected && cell.type === item.type) { // 鏁版嵁鏈慨鏀�
-            items.push(item)
-          } else if (cell.selected) { // 鏁版嵁绫诲瀷淇敼
-            if (cell.type === 'text') {
-              item.match = textmatch[cell.datatype]
-            } else if (cell.type === 'select') {
-              item.match = selectmatch[cell.datatype]
-            } else if (cell.type === 'daterange') {
-              item.match = datematch[cell.datatype]
-            } else {
-              cell.type = 'text'
-              item.match = textmatch[cell.datatype]
-            }
-            
-            item.type = cell.type
-            item.initval = ''
-            items.push(item)
-          }
-          columnsMap.delete(item.field)
-        } else if (!item.origin) {
-          items.push(item)
-        }
-      })
-
-      let _columns = [...columnsMap.values()]
-
-      _columns.forEach(item => {
-        if (item.selected) {
-          let _match = ''
-          if (item.type === 'text') {
-            _match = textmatch[item.datatype]
-          } else if (item.type === 'select') {
-            _match = selectmatch[item.datatype]
-          } else if (item.type === 'daterange') {
-            _match = datematch[item.datatype]
-          } else {
-            item.type = 'text'
-            _match = textmatch[item.datatype]
-          }
-
-          let newcard = {
-            uuid: Utils.getuuid(),
-            label: item.label,
-            field: item.field,
-            initval: '',
-            type: item.type,
-            resourceType: '0',
-            setAll: 'false',
-            options: [],
-            dataSource: '',
-            linkField: '',
-            valueField: '',
-            valueText: '',
-            orderBy: '',
-            orderType: 'asc',
-            match: _match,
-            display: 'dropdown'
-          }
-
-          items.push(newcard)
-        }
-      })
-    } else {
-      config.columns.forEach(item => {
-        if (columnsMap.has(item.field)) {
-          let cell = columnsMap.get(item.field)
-
-          if (cell.selected) {
-            items.push(item)
-          }
-          columnsMap.delete(item.field)
-        } else if (!item.origin) {
-          items.push(item)
-        }
-      })
-
-      let _columns = [...columnsMap.values()]
-
-      _columns.forEach(item => {
-        if (item.selected) {
-          let newcard = {
-            uuid: Utils.getuuid(),
-            Align: 'left',
-            label: item.label,
-            field: item.field,
-            Hide: 'false',
-            IsSort: item.type === 'picture' ? 'false' : 'true',
-            type: item.type,
-            Width: 120
-          }
-
-          items.push(newcard)
-        }
-      })
-    }
-
-    this.setState({
-      config: {...config, [addType]: items}
-    })
-
-    notification.success({
-      top: 92,
-      message: '鎿嶄綔鎴愬姛',
-      duration: 2
-    })
-  }
-
-  onTableChange = (value) => {
-    const {tables, selectedTables, tableColumns} = this.state
-
-    let _table = tables.filter(item => item.TbName === value)[0]
-    let isSelected = !!selectedTables.filter(cell => cell.TbName === value)[0]
-    if (!isSelected) {
-      this.setState({
-        selectedTables: [...selectedTables, _table]
-      })
-      Api.getSystemConfig({func: 'sPC_Get_FieldName', TBName: value}).then(res => {
-        if (res.status) {
-          let tabmsg = {
-            tableName: _table.name,
-            columns: res.FDName.map(item => {
-              let _type = item.FieldType.toLowerCase()
-              let _decimal = 0
-              if (/^nvarchar/.test(_type)) {
-                _type = 'text'
-              } else if (/^int/.test(_type)) {
-                _type = 'number'
-              } else if (/^decimal/.test(_type)) {
-                _decimal = _type.split(',')[1]
-                _decimal = parseInt(_decimal)
-                _type = 'number'
-              } else if (/^datetime/.test(_type)) {
-                _type = 'datetime'
-              } else if (/^date/.test(_type)) {
-                _type = 'date'
-              } else {
-                _type = 'text'
-              }
-
-              return {
-                field: item.FieldName,
-                label: item.FieldDec,
-                type: _type,
-                datatype: _type,
-                decimal: _decimal
-              }
-            })
-          }
-          this.setState({
-            tableColumns: [...tableColumns, tabmsg]
-          })
-        } else {
-          notification.warning({
-            top: 92,
-            message: res.message,
-            duration: 5
-          })
-        }
-      })
-    }
-  }
-
-  deleteTable = (table) => {
-    const {selectedTables, tableColumns} = this.state
-
-    this.setState({
-      selectedTables: selectedTables.filter(item => item.TbName !== table.TbName),
-      tableColumns: tableColumns.filter(item => item.tableName !== table.TbName)
-    })
   }
 
   changeSetting = () => {
@@ -2049,6 +1021,9 @@
     }
   }
 
+  /**
+   * @description 鍒囨崲鏍囩鏄惁鍚敤
+   */
   onEnabledChange = () => {
     const { config } = this.state
 
@@ -2069,66 +1044,6 @@
         config: {...config, enabled: !config.enabled}
       })
     }
-  }
-
-  onColumnNameChange = () => {
-    const { showColumnName, config } = this.state
-
-    if (!showColumnName) {
-      let fields = []
-      config.columns.forEach(col => {
-        if (col.field) {
-          fields.push(col.field)
-        }
-      })
-
-      fields = fields.join(',')
-
-      let textArea = document.createElement('textarea')
-      textArea.value = fields
-      document.body.appendChild(textArea)
-      textArea.select()
-
-      try {
-        document.execCommand('copy')
-        document.body.removeChild(textArea)
-      } catch (err) {
-        document.body.removeChild(textArea)
-      }
-    }
-
-    this.setState({
-      showColumnName: !showColumnName
-    })
-  }
-
-  /**
-   * @description 鍒涘缓鎸夐挳鎺ュ彛锛堝啓鍏ワ級
-   */
-  btnCreatInterface = () => {
-    const { config } = this.state
-
-    this.menuformRef.handleConfirm().then(res => {
-      this.actionFormRef.handleConfirm().then(result => {
-        if (!['pop', 'exec', 'prompt'].includes(result) || result.funcType || result.intertype !== 'inner' || result.innerFunc ) {
-          notification.warning({
-            top: 92,
-            message: '鎵撳紑鏂瑰紡涓� 寮圭獥锛堣〃鍗曪級銆佹彁绀烘鎴栫洿鎺ユ墽琛岋紝涓斾娇鐢ㄧ郴缁熷嚱鏁版椂锛屾墠鍙互鍒涘缓鎺ュ彛锛�',
-            duration: 5
-          })
-          return
-        }
-        
-        let _menu = {
-          type: 'subtable',
-          MenuID: config.uuid,
-          menuName: res.tabName,
-          menuNo: res.tabNo
-        }
-        
-        this.refs.btnCreatInterface.triggerInInterface(result, config, _menu)
-      })
-    })
   }
 
   /**
@@ -2161,27 +1076,9 @@
     })
   }
 
-  copycolumn = () => {
-    const { config } = this.state
-
-    let oInput = document.createElement('input')
-    let val = {
-      copyType: 'columns',
-      columns: config.columns
-    }
-
-    oInput.value = window.btoa(window.encodeURIComponent(JSON.stringify(val)))
-    document.body.appendChild(oInput)
-    oInput.select()
-    document.execCommand('Copy')
-    oInput.className = 'oInput'
-    oInput.style.display = 'none'
-
-    message.success('澶嶅埗鎴愬姛銆�')
-
-    document.body.removeChild(oInput)
-  }
-
+  /**
+   * @description 缂栬緫鍔熻兘瀹屾垚鏇存柊锛屽寘鎷В鍐绘寜閽�佺矘璐淬�佹浛鎹㈢瓑
+   */
   updateConfig = (res) => {
     if (res.type === 'thaw') {
       this.setState({
@@ -2189,36 +1086,119 @@
         config: res.config
       })
     } else if (res.type === 'paste') {
-      if (res.copyType === 'action') {
-        this.handleAction(res.content, 'copy')
-      } else if (res.copyType === 'columns') {
+      this.setState({
+        pasteContent: res.content
+      }, () => {
         this.setState({
-          config: res.config
+          pasteContent: null
         })
-      }
+      })
     }
   }
 
+  /**
+   * @description 鍥捐〃閰嶇疆淇敼鍚庝繚瀛�
+   */
+  updateChart = (plot) => {
+    const { config } = this.state
+    let _charts = JSON.parse(JSON.stringify(config.charts))
+
+    _charts = _charts.map(item => {
+      if (item.uuid === plot.uuid) {
+        if (!is(fromJS(item), fromJS(plot))) {
+          let _element = document.getElementById(plot.uuid)
+          if (_element) {
+            _element.innerHTML = ''
+          }
+        }
+        return plot
+      }
+      return item
+    })
+
+    this.setState({
+      config: {...config, charts: _charts}
+    })
+  }
+
+  /**
+   * @description 鏇存柊鎼滅储鏉′欢閰嶇疆淇℃伅
+   */
+  updatesearch = (config, options) => {
+    const { optionLibs } = this.state
+
+    this.setState({
+      config: config,
+      optionLibs: options || optionLibs
+    })
+  }
+
+  /**
+   * @description 鏇存柊鎸夐挳閰嶇疆淇℃伅
+   */
+  updateaction = (config, copyId, delcard) => {
+    const { copyActions, delActions } = this.state
+
+    this.setState({
+      config: config,
+      copyActions: copyId ? [...copyActions, copyId] : copyActions,
+      delActions: delcard ? [...delActions, delcard] : delActions
+    })
+  }
+
+  /**
+   * @description 鏇存柊鏄剧ず鍒楅厤缃俊鎭�
+   */
+  updatecolumn = (config) => {
+    this.setState({
+      config: config
+    })
+  }
+
+  /**
+   * @description 鏇存柊鍥捐〃缁勯厤缃俊鎭�
+   */
+  updatechartgroup = (config, _chartview) => {
+    this.setState({
+      config: config,
+      chartview: _chartview
+    })
+  }
+  
+  /**
+   * @description 鏇存柊甯哥敤琛ㄤ俊鎭紝蹇嵎娣诲姞鍚庢洿鏂伴厤缃俊鎭�
+   */
+  updatetable = (config, fields) => {
+    const { tableFields } = this.state
+
+    this.setState({
+      config: config,
+      tableFields: fields ? fields : tableFields
+    })
+  }
+
+  /**
+   * @description 鎵归噺娣诲姞锛屾洿鏂伴厤缃俊鎭�
+   */
+  updatefield = (config) => {
+    this.setState({
+      config: config
+    })
+  }
+
   render () {
-    const { modaltype, activeKey, config } = this.state
+    const { activeKey, config, chartview } = this.state
 
-    const configAction = config.action.filter(_action =>
-      !_action.origin && (_action.OpenType === 'pop' || _action.OpenType === 'popview' || _action.OpenType === 'blank' || _action.OpenType === 'tab')
-    )
-
-    let hasbtncrtinter = false
-    if (modaltype === 'actionEdit' && config.setting.interType === 'inner' && !config.setting.innerFunc && config.setting.dataresource) {
-      hasbtncrtinter = true
-    }
+    const confActions = config.action.filter(_action => !_action.origin && ['pop', 'popview', 'blank', 'tab'].includes(_action.OpenType))
 
     return (
-      <div className="common-table-board">
+      <div className="model-subtable-board">
         <DndProvider backend={HTML5Backend}>
           {/* 宸ュ叿鏍� */}
           <div className="tools">
             <Collapse accordion defaultActiveKey={activeKey} bordered={false} onChange={(key) => this.setState({activeKey: key})}>
               {/* 鍩烘湰淇℃伅 */}
-              <Panel forceRender={true} header={'鏍囩鍩烘湰淇℃伅'} key="0" id="common-basedata">
+              <Panel forceRender={true} header={'鏍囩鍩烘湰淇℃伅'} key="0" id="subtable-basedata">
                 {/* 鑿滃崟淇℃伅 */}
                 <MenuForm
                   dict={this.state.dict}
@@ -2226,42 +1206,12 @@
                   wrappedComponentRef={(inst) => this.menuformRef = inst}
                 />
                 {/* 琛ㄥ悕娣诲姞 */}
-                <div className="ant-col ant-form-item-label">
-                  <label>
-                    <Tooltip placement="topLeft" title="姝ゅ鍙互娣诲姞閰嶇疆鐩稿叧鐨勫父鐢ㄨ〃锛屽湪娣诲姞鎼滅储鏉′欢鍜屾樉绀哄垪鏃讹紝鍙�氳繃宸ュ叿鏍忎腑鐨勬坊鍔犳寜閽紝鎵归噺娣诲姞琛ㄦ牸鐩稿叧瀛楁銆�">
-                      <Icon type="question-circle" />
-                      {this.state.dict['header.menu.table.add']}
-                    </Tooltip>
-                  </label>
-                </div>
-                <Select
-                  showSearch
-                  className="tables"
-                  style={{ width: '100%' }}
-                  optionFilterProp="children"
-                  value={this.state.dict['header.menu.table.placeholder']}
-                  onChange={this.onTableChange}
-                  showArrow={false}
-                  getPopupContainer={() => document.getElementById('common-basedata')}
-                  filterOption={(input, option) => {
-                    return option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0 ||
-                      option.props.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
-                  }}
-                > 
-                  {this.state.tables.map((table, index) => (
-                    <Option key={index} title={table.TbName} value={table.TbName}>{table.Remark}</Option>
-                  ))}
-                </Select>
-                {this.state.selectedTables.length > 0 && <List
-                  size="small"
-                  bordered
-                  dataSource={this.state.selectedTables}
-                  renderItem={(item, index) => <List.Item key={index} title={item.Remark + ' (' + item.TbName + ')'}>
-                    {item.Remark + ' (' + item.TbName + ')'}
-                    <Icon type="close" onClick={() => this.deleteTable(item)}/>
-                    <div className="bottom-mask"></div>
-                  </List.Item>}
-                />}
+                <TableComponent
+                  config={config}
+                  containerId="subtable-basedata"
+                  selectedTables={config.tables || []}
+                  updatetable={this.updatetable}
+                />
               </Panel>
               {/* 鎼滅储鏉′欢娣诲姞 */}
               <Panel header={this.state.dict['header.menu.search']} key="1">
@@ -2270,7 +1220,12 @@
                     return (<SourceElement key={index} content={item}/>)
                   })}
                 </div>
-                <Button type="primary" block onClick={() => this.queryField('search')}>{this.state.dict['header.menu.search.add']}</Button>
+                <FieldsComponent
+                  config={config}
+                  type="search"
+                  tableFields={this.state.tableFields}
+                  updatefield={this.updatefield}
+                />
               </Panel>
               {/* 鎸夐挳娣诲姞 */}
               <Panel header={this.state.dict['header.menu.action']} key="2">
@@ -2280,7 +1235,7 @@
                   })}
                 </div>
                 <div className="config-btn">
-                  {configAction.length > 0 ?
+                  {confActions.length > 0 ?
                     <p className="config-btn-title">
                       <Tooltip placement="topLeft" title="鐐瑰嚮鎸夐挳锛屽彲瀹屾垚鎴栨煡鐪嬫寜閽厤缃俊鎭��">
                         <Icon type="question-circle" />
@@ -2289,7 +1244,7 @@
                     </p> : null
                   }
                 </div>
-                {configAction.map((item, index) => {
+                {confActions.map((item, index) => {
                   return (
                     <div key={index}>
                       <Button
@@ -2309,7 +1264,12 @@
                     return (<SourceElement key={index} content={item}/>)
                   })}
                 </div>
-                <Button type="primary" block onClick={() => this.queryField('columns')}>{this.state.dict['header.menu.column.add']}</Button>
+                <FieldsComponent
+                  config={config}
+                  type="columns"
+                  tableFields={this.state.tableFields}
+                  updatefield={this.updatefield}
+                />
               </Panel>
             </Collapse>
           </div>
@@ -2317,7 +1277,7 @@
             <Card title={
               <div>
                 鏍囩锛堝瓙琛級椤甸潰閰嶇疆 
-                <Icon type="redo" style={{marginLeft: '10px'}} title="鍒锋柊鏍囩鍒楄〃" onClick={this.reloadTab} />
+                <Icon type="redo" style={{marginLeft: '10px'}} title="鍒锋柊鏍囩鍒楄〃" onClick={() => this.reloadTab(true)} />
               </div>
             } bordered={false} extra={
               <div>
@@ -2328,245 +1288,68 @@
               </div>
             } style={{ width: '100%' }}>
               <Icon type="setting" onClick={this.changeSetting} />
-              <div className="search-list">
-                <Tooltip placement="bottomLeft" overlayClassName="middle" title="鍦ㄥ乏渚у伐鍏锋爮銆婃悳绱€�嬩腑锛岄�夋嫨瀵瑰簲鎼滅储妗嗘嫋鑷虫澶勬坊鍔狅紱鎴栫偣鍑绘寜閽�婃坊鍔犳悳绱㈡潯浠躲�嬫壒閲忔坊鍔狅紝閫夋嫨鎵归噺娣诲姞鏃讹紝闇�鎻愬墠閫夋嫨浣跨敤琛ㄣ��">
-                  <Icon type="question-circle" />
-                </Tooltip>
-                <DragElement
-                  type="search"
-                  list={this.state.config.search}
-                  handleList={this.handleList}
-                  handleMenu={this.handleSearch}
-                  deleteMenu={this.deleteElement}
-                  placeholder={this.state.dict['header.form.search.placeholder']}
+              <SearchComponent
+                menu={{MenuID: this.state.config.uuid, MenuName: this.state.config.tabName}}
+                config={this.state.config}
+                pasteContent={this.state.pasteContent}
+                sysRoles={this.props.sysRoles}
+                optionLibs={this.state.optionLibs}
+                updatesearch={this.updatesearch}
+              />
+              <div className="chart-view" style={{position: 'relative'}}>
+                {/* 瑙嗗浘缁� */}
+                <ChartGroupComponent
+                  config={config}
+                  sysRoles={this.props.sysRoles}
+                  updatechartgroup={this.updatechartgroup}
                 />
-              </div>
-              {/* <div className="action-list">
-                <DragElement
-                  type="action"
-                  list={this.state.config.action}
-                  setting={this.state.config.setting}
-                  handleList={this.handleList}
-                  handleMenu={this.handleAction}
-                  copyElement={(val) => this.handleAction(val, 'copy')}
-                  deleteMenu={this.deleteElement}
-                  profileMenu={this.profileAction}
-                  doubleClickCard={this.btnDoubleClick}
-                  placeholder={this.state.dict['header.form.action.placeholder']}
-                />
-              </div> */}
-              <div className="action-list">
-                <Tooltip placement="bottomLeft" overlayClassName="middle" title="鍦ㄥ乏渚у伐鍏锋爮銆婃寜閽�嬩腑锛岄�夋嫨瀵瑰簲绫诲瀷鐨勬寜閽嫋鑷虫澶勬坊鍔狅紝濡傞�夋嫨鎸夐挳绫诲瀷涓鸿〃鍗曘�佹柊鏍囩椤电瓑鍚湁閰嶇疆椤甸潰鐨勬寜閽紝鍙湪宸︿晶宸ュ叿鏍�-鎸夐挳-鍙厤缃寜閽锛岀偣鍑绘寜閽畬鎴愮浉鍏抽厤缃�傛敞锛氬綋璁剧疆鎸夐挳鏄剧ず浣嶇疆涓鸿〃鏍兼椂锛屾樉绀哄垪浼氬鍔犳搷浣滃垪銆�">
-                  <Icon type="question-circle" />
-                </Tooltip>
-                <DragElement
-                  type="action"
-                  list={this.state.config.action}
-                  setting={this.state.config.setting}
-                  handleList={this.handleList}
-                  handleMenu={this.handleAction}
-                  copyElement={(val) => this.handleAction(val, 'copy')}
-                  deleteMenu={this.deleteElement}
-                  profileMenu={this.profileAction}
-                  doubleClickCard={this.btnDoubleClick}
-                  placeholder={this.state.dict['header.form.action.placeholder']}
-                />
-              </div>
-              <div className="column-list">
-                <Tooltip placement="bottomLeft" overlayClassName="middle" title="鍦ㄥ乏渚у伐鍏锋爮銆婃樉绀哄垪銆嬩腑锛岄�夋嫨瀵瑰簲绫诲瀷鐨勬樉绀哄垪鎷栬嚦姝ゅ娣诲姞锛涙垨鐐瑰嚮銆婃坊鍔犳樉绀哄垪銆嬫寜閽壒閲忔坊鍔狅紝閫夋嫨鎵归噺娣诲姞鏃讹紝闇�鎻愬墠閫夋嫨浣跨敤琛ㄣ�傛敞锛氭坊鍔犲悎骞跺垪鏃讹紝闇�璁剧疆鍙�夊垪銆�">
-                  <Icon type="question-circle" />
-                </Tooltip>
-                {config.columns && config.columns.length > 0 ? <Icon className="column-copy" title="copy" type="copy" onClick={this.copycolumn} /> : null}
-                <Switch checkedChildren="寮�" unCheckedChildren="鍏�" defaultChecked={this.state.showColumnName} onChange={this.onColumnNameChange} />
-                <DragElement
-                  type="columns"
-                  list={this.state.config.columns}
-                  setting={this.state.config.setting}
-                  gridBtn={this.state.config.gridBtn}
-                  handleList={this.handleList}
-                  handleMenu={this.handleColumn}
-                  deleteMenu={this.deleteElement}
-                  handleGridBtn={this.handleGridBtn}
-                  showfield={this.state.showColumnName}
-                  placeholder={this.state.dict['header.form.column.placeholder']}
-                />
+                {config.charts.map(item => {
+                  if (!config.expand && chartview !== item.uuid) return ''
+
+                  if (item.chartType === 'table') {
+                    return (
+                      <Col span={item.width || 24} key={item.uuid}>
+                        {config.charts.length > 1 ? <p className="chart-title">{item.title}</p> : null}
+                        <ActionComponent
+                          type="subtable"
+                          menu={{MenuID: config.uuid, MenuName: config.tabName, MenuNo: config.tabNo}}
+                          config={config}
+                          tabs={this.state.tabviews}
+                          pasteContent={this.state.pasteContent}
+                          usefulFields={this.props.permFuncField}
+                          setSubConfig={this.setSubConfig}
+                          updateaction={this.updateaction}
+                        />
+                        <ColumnComponent
+                          config={config}
+                          menu={this.props.menu}
+                          sysRoles={this.props.sysRoles}
+                          pasteContent={this.state.pasteContent}
+                          updatecolumn={this.updatecolumn}
+                        />
+                      </Col>
+                    )
+                  } else {
+                    return (
+                      <Col span={item.width} key={item.uuid}>
+                        <ChartComponent
+                          type={item.chartType}
+                          dict={this.state.dict}
+                          columns={config.columns}
+                          plotchange={this.updateChart}
+                          plot={item}
+                        />
+                      </Col>
+                    )
+                  }
+                })}
               </div>
             </Card>
           </div>
         </DndProvider>
-        {/* 缂栬緫鎼滅储鏉′欢 */}
-        <Modal
-          title={this.state.dict['header.modal.search.edit']}
-          visible={modaltype === 'search'}
-          width={750}
-          maskClosable={false}
-          onOk={this.handleSubmit}
-          confirmLoading={this.state.sqlVerifing}
-          onCancel={this.editModalCancel}
-          destroyOnClose
-        >
-          <SearchForm
-            dict={this.state.dict}
-            card={this.state.card}
-            formlist={this.state.formlist}
-            inputSubmit={this.handleSubmit}
-            optionLibs={this.state.optionLibs}
-            wrappedComponentRef={(inst) => this.searchFormRef = inst}
-          />
-        </Modal>
-        {/* 缂栬緫鎸夐挳锛氬鍒躲�佺紪杈� */}
-        <Modal
-          title={modaltype === 'actionEdit' ? this.state.dict['header.modal.action.edit'] : this.state.dict['header.modal.action.copy']}
-          visible={modaltype === 'actionEdit' || modaltype === 'actionCopy'}
-          width={750}
-          maskClosable={false}
-          onCancel={this.editModalCancel}
-          footer={[
-            hasbtncrtinter ? <CreateInterface key="interface" dict={this.state.dict} ref="btnCreatInterface" trigger={this.btnCreatInterface}/> : null,
-            modaltype === 'actionEdit' ? <CreateFunc key="create" dict={this.state.dict} ref="btnCreatFunc" trigger={this.creatFunc}/> : null,
-            <Button key="cancel" onClick={this.editModalCancel}>{this.state.dict['header.cancel']}</Button>,
-            <Button key="confirm" type="primary" onClick={this.handleSubmit}>{this.state.dict['header.confirm']}</Button>
-          ]}
-          destroyOnClose
-        >
-          <ActionForm
-            dict={this.state.dict}
-            card={this.state.card}
-            tabs={this.state.tabviews}
-            formlist={this.state.formlist}
-            inputSubmit={this.handleSubmit}
-            setting={this.state.config.setting}
-            wrappedComponentRef={(inst) => this.actionFormRef = inst}
-          />
-        </Modal>
-        {/* 鏄剧ず鍒楃紪杈� */}
-        <Modal
-          title={this.state.dict['header.modal.column.edit']}
-          visible={modaltype === 'columns'}
-          width={750}
-          maskClosable={false}
-          onOk={this.handleSubmit}
-          onCancel={this.editModalCancel}
-          destroyOnClose
-        >
-          <ColumnForm
-            dict={this.state.dict}
-            card={this.state.card}
-            MenuID={this.props.menu.MenuID}
-            inputSubmit={this.handleSubmit}
-            formlist={this.state.formlist}
-            wrappedComponentRef={(inst) => this.columnFormRef = inst}
-          />
-        </Modal>
-        {/* 鍚堝苟鍒楃紪杈� */}
-        <Modal
-          title={this.state.dict['header.modal.colspan.edit']}
-          visible={modaltype === 'colspan'}
-          width={750}
-          maskClosable={false}
-          onOk={this.handleSubmit}
-          onCancel={this.editModalCancel}
-          destroyOnClose
-        >
-          <ColspanForm
-            dict={this.state.dict}
-            card={this.state.card}
-            inputSubmit={this.handleSubmit}
-            columns={this.state.config.columns}
-            wrappedComponentRef={(inst) => this.columnFormRef = inst}
-          />
-        </Modal>
-        {/* 鎿嶄綔鍒楃紪杈� */}
-        <Modal
-          title={this.state.dict['header.modal.gridbtn.edit']}
-          visible={modaltype === 'gridbtn'}
-          width={700}
-          maskClosable={false}
-          onOk={this.handleSubmit}
-          onCancel={this.editModalCancel}
-          destroyOnClose
-        >
-          <GridBtnForm
-            dict={this.state.dict}
-            inputSubmit={this.handleSubmit}
-            card={this.state.config.gridBtn}
-            wrappedComponentRef={(inst) => this.gridBtnFormRef = inst}
-          />
-        </Modal>
-        {/* 鏍规嵁瀛楁鍚嶆坊鍔犳樉绀哄垪鍙婃悳绱㈡潯浠� */}
-        <Modal
-          wrapClassName="common-table-fields-modal"
-          title={this.state.dict['header.edit']}
-          visible={this.state.tableVisible}
-          width={'65vw'}
-          maskClosable={false}
-          style={{minWidth: '900px', maxWidth: '1200px'}}
-          cancelText={this.state.dict['header.close']}
-          onOk={this.addFieldSubmit}
-          onCancel={() => { // 鍙栨秷娣诲姞
-            this.setState({
-              tableVisible: false,
-              addType: ''
-            })
-          }}
-          destroyOnClose
-        >
-          {this.state.addType && this.state.fields.length > 0 ?
-            <EditCard data={this.state.fields} ref="searchcard" type={this.state.addType} dict={this.state.dict} /> : null
-          }
-          {(!this.state.fields || this.state.fields.length === 0) &&
-            <Empty />
-          }
-        </Modal>
-        {/* 鎸夐挳浣跨敤绯荤粺瀛樺偍杩囩▼鏃讹紝楠岃瘉淇℃伅妯℃�佹 */}
-        <Modal
-          wrapClassName="common-table-fields-modal"
-          title={'楠岃瘉淇℃伅'}
-          visible={this.state.profileVisible}
-          width={'75vw'}
-          maskClosable={false}
-          style={{minWidth: '900px', maxWidth: '1200px'}}
-          okText={this.state.dict['header.submit']}
-          onOk={this.verifySubmit}
-          onCancel={() => { this.setState({ profileVisible: false }) }}
-          destroyOnClose
-        >
-          {this.state.card && !this.state.card.execMode && this.state.card.OpenType !== 'excelIn' && this.state.card.OpenType !== 'excelOut' ?
-            <VerifyCard
-              floor="subtable"
-              card={this.state.card}
-              dict={this.state.dict}
-              columns={this.state.config.columns}
-              wrappedComponentRef={(inst) => this.verifyRef = inst}
-            /> : null
-          }
-          {this.state.card && this.state.card.execMode ?
-            <VerifyCardPrint
-              card={this.state.card}
-              dict={this.state.dict}
-              columns={config.columns}
-              wrappedComponentRef={(inst) => this.verifyRef = inst}
-            /> : null
-          }
-          {this.state.card && this.state.card.OpenType === 'excelIn' ?
-            <VerifyCardExcelIn
-              card={this.state.card}
-              dict={this.state.dict}
-              columns={this.state.config.columns}
-              wrappedComponentRef={(inst) => this.verifyRef = inst}
-            /> : null
-          }
-          {this.state.card && this.state.card.OpenType === 'excelOut' ?
-            <VerifyCardExcelOut
-              card={this.state.card}
-              dict={this.state.dict}
-              wrappedComponentRef={(inst) => this.verifyRef = inst}
-            /> : null
-          }
-        </Modal>
         {/* 璁剧疆鍏ㄥ眬閰嶇疆鍙婂垪琛ㄦ暟鎹簮 */}
         <Modal
-          title={this.state.dict['header.edit']}
+          title={this.state.dict['model.edit']}
           visible={this.state.settingVisible}
           width={750}
           maskClosable={false}
@@ -2579,7 +1362,7 @@
             <CreateInterface key="interface" dict={this.state.dict} ref="tableCreatInterface" trigger={this.tableCreatInterface}/>,
             <CreateFunc key="create" dict={this.state.dict} ref="tableCreatFunc" trigger={this.tableCreatFunc}/>,
             <Button key="cancel" onClick={() => { this.setState({ settingVisible: false }) }}>{this.state.dict['header.cancel']}</Button>,
-            <Button key="confirm" type="primary" loading={this.state.sqlVerifing} onClick={this.settingSave}>{this.state.dict['header.confirm']}</Button>
+            <Button key="confirm" type="primary" loading={this.state.sqlVerifing} onClick={this.settingSave}>{this.state.dict['model.confirm']}</Button>
           ]}
           destroyOnClose
         >
diff --git a/src/templates/subtableconfig/index.scss b/src/templates/subtableconfig/index.scss
index 6d596e6..3987f11 100644
--- a/src/templates/subtableconfig/index.scss
+++ b/src/templates/subtableconfig/index.scss
@@ -1,4 +1,4 @@
-.common-table-board {
+.model-subtable-board {
   position: fixed;
   z-index: 1070;
   padding-top: 48px;
@@ -58,11 +58,6 @@
         margin-bottom: 10px;
         color: #1890ff;
         border-bottom: 1px solid #e8e8e8;
-      }
-    }
-    .tables {
-      .ant-select-selection-selected-value {
-        opacity: 0.4!important;
       }
     }
     .ant-list {
@@ -133,7 +128,6 @@
     position: relative;
     width: calc(100vw - 235px);
     height: 100%;
-    // overflow-y: hidden;
     background: #ffffff;
     .ant-switch.big {
       min-width: 60px;
@@ -164,217 +158,23 @@
     .ant-card-body {
       position: relative;
       padding: 0;
+      
+      .chart-view {
+        margin-bottom: 70px;
 
-      .search-list {
-        padding: 1px 24px 20px;
-        min-height: 87px;
-        border-bottom: 1px solid #d9d9d9;
-        > .ant-row {
-          min-height: 65px;
-        }
-        .ant-row .ant-col-6 {
-          padding: 0 12px!important;
-        }
-        .ant-row.ant-form-item .ant-col {
-          padding: 0;
-        }
-        .page-card {
-          position: relative;
-          background: #ffffff;
-          border-radius: 2px;
-          padding-top: 15px;
-          .ant-form-item {
-            cursor: move;
-            display: flex;
-            margin-bottom: 0px;
-            .ant-form-item-label {
-              // width: 100px;
-              height: 40px;
-              label {
-                width: 100%;
-                cursor: move;
-                overflow: hidden;
-                display: inline-block;
-                text-overflow: ellipsis;
-                white-space: nowrap;
-              }
-            }
-            .ant-form-item-control-wrapper {
-              flex: 1 1;
-              .ant-select {
-                width: 100%;
-                margin-top: 4px;
-              }
-              .ant-calendar-picker {
-                margin-top: 4px;
-              }
-              .input-mask {
-                position: absolute;
-                top: 0;
-                left: 0;
-                right: 0;
-                bottom: 0;
-                opacity: 0;
-                z-index: 2;
-              }
-              .data-range .ant-calendar-picker-input {
-                padding: 4px 20px 4px 5px;
-                font-size: 13px;
-              }
-            }
-          }
-          .edit {
-            position: absolute;
-            left: 0;
-            top: 5px;
-            color: #1890ff;
-            cursor: pointer;
-            display: none;
-          }
-          .edit.close {
-            left: 20px;
-            color: #ff4d4f;
-          }
-        }
-        .page-card:hover {
-          .edit {
-            display: inline-block;
-          }
-        }
-        .ant-calendar-picker {
-          min-width: 100px!important;
-          width: 100%;
-        }
-      }
-      .action-list {
-        padding: 0px 20px 15px;
-        min-height: 82px;
-        > .ant-row {
-          min-height: 80px;
-        }
-        .page-card {
-          display: inline-block;
-          margin: 0px 0px 0px 0px;
-          padding: 15px 10px 0 0;
-          position: relative;
-          div {
-            cursor: move;
-          }
-          .edit {
-            position: absolute;
-            left: 0;
-            top: 0px;
-            color: #1890ff;
-            cursor: pointer;
-            display: none;
-          }
-          .edit.close {
-            left: 40px;
-            color: #ff4d4f;
-          }
-          .edit.copy {
-            left: 20px;
-            color: #26C281;
-          }
-          button {
-            cursor: move;
-            .anticon-table {
-              font-size: 10px;
-              position: absolute;
-              right: 1px;
-              bottom: 0px;
-            }
-          }
-        }
-        .page-card:hover {
-          .edit {
-            display: inline-block;
-          }
-        }
-      }
-      .column-list {
-        position: relative;
-        padding: 0px 20px;
-        .ant-switch {
-          position: absolute;
-          right: 20px;
-          top: -10px;
-        }
-        .column-copy {
-          position: absolute;
-          font-size: 16px;
-          right: 75px;
-          top: -7px;
-          color: #26C281;
-        }
-        > .ant-row {
-          background: #fafafa;
-          border-radius: 4px;
-          min-height: 47px;
-          border: 1px solid #e8e8e8;
-          .column-box {
-            display: flex;
-          }
-          .column-box:not(:first-child) {
-            border-top: 1px solid #e8e8e8;
-          }
-          .page-card {
-            position: relative;
-            padding: 0px;
-            min-height: 45px;
-            > div {
-              padding: 12px 0px 0px;
-              cursor: move;
-              height: 100%;
-              .ant-table-column-sorters {
-                padding: 0px 8px 12px;
-              }
-              .ant-table-column-fields {
-                padding: 0px 8px 5px;
-              }
-            }
-            .ant-table-column-sorter {
-              position: relative;
-              display: inline-block;
-              width: 24px;
-              font-size: 12px;
-              color: #bfbfbf;
-              .anticon-caret-up {
-                position: relative;
-                left: 10px;
-                top: -3px;
-              }
-              .anticon-caret-down {
-                position: relative;
-                left: -2px;
-                top: 3px;
-              }
-            }
-            .edit {
-              position: absolute;
-              left: 0;
-              top: 0px;
-              color: #1890ff;
-              cursor: pointer;
-              display: none;
-            }
-            .edit.close {
-              left: 20px;
-              color: #ff4d4f;
-            }
-            .ant-checkbox-inner {
-              margin-top: 14px;
-              margin-left: calc(50% - 8px);
-            }
-          }
-          .page-card:hover {
-            .edit {
-              display: inline-block;
-            }
-          }
-          .page-card:not(:last-child) {
-            border-right: 1px solid #e8e8e8;
-          }
+        .chart-title {
+          margin-bottom: 15px;
+          color: rgba(0, 0, 0, 0.85);
+          font-weight: 400;
+          font-size: 18px;
+          line-height: 25px;
+          height: 35px;
+          text-overflow: ellipsis;
+          white-space: nowrap;
+          overflow: hidden;
+          max-width: 50%;
+          padding-top: 10px;
+          padding-left: 30px;
         }
       }
       > .anticon-setting {
@@ -416,33 +216,5 @@
     position: absolute;
     margin-left: calc(50vw - 22px);
     margin-top: 30vh;
-  }
-}
-
-.common-table-fields-modal {
-  .ant-modal {
-    top: 50px;
-    padding-bottom: 5px;
-    .ant-modal-body {
-      max-height: calc(100vh - 190px);
-      overflow-y: auto;
-      .ant-empty {
-        margin: 15vh 8px;
-      }
-    }
-    .ant-modal-body::-webkit-scrollbar {
-      width: 7px;
-    }
-    .ant-modal-body::-webkit-scrollbar-thumb {
-      border-radius: 5px;
-      box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
-      background: rgba(0, 0, 0, 0.13);
-    }
-    .ant-modal-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);
-    }
   }
 }
diff --git a/src/templates/subtableconfig/source.jsx b/src/templates/subtableconfig/source.jsx
index 9a6c5cc..ba636c4 100644
--- a/src/templates/subtableconfig/source.jsx
+++ b/src/templates/subtableconfig/source.jsx
@@ -1,6 +1,6 @@
 import Utils from '@/utils/utils.js'
-import zhCN from '@/locales/zh-CN/comtable.js'
-import enUS from '@/locales/en-US/comtable.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
 
 const CommonDict = (!localStorage.getItem('lang') || localStorage.getItem('lang') === 'zh-CN') ? zhCN : enUS
 
@@ -168,7 +168,17 @@
       style: 'button',
       show: 'horizontal',
       Width: 120
-    }
+    },
+    expand: false,
+    charts: [{
+      uuid: Utils.getuuid(),
+      label: '',
+      title: '',
+      chartType: 'table',
+      icon: 'table',
+      Hide: 'false',
+      blacklist: []
+    }]
   }
 
   searchItems = [
diff --git a/src/templates/zshare/chartcompile/index.jsx b/src/templates/zshare/chartcompile/index.jsx
new file mode 100644
index 0000000..3ea5f49
--- /dev/null
+++ b/src/templates/zshare/chartcompile/index.jsx
@@ -0,0 +1,213 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+// import { is, fromJS } from 'immutable'
+import { Drawer, Form, Button, Col, Row, Select, Icon, Radio, Tooltip, Input, InputNumber } from 'antd'
+
+import { getChartOptionForm } from '@/templates/zshare/formconfig'
+import './index.scss'
+
+class LineChartDrawerForm extends Component {
+  static propTpyes = {
+    type: PropTypes.string,
+    dict: PropTypes.object,
+    plot: PropTypes.object,
+    columns: PropTypes.array,
+    plotchange: PropTypes.func
+  }
+
+  state = {
+    visible: false,
+    formlist: null
+  }
+
+  showDrawer = () => {
+    const { columns, plot, type } = this.props
+
+    this.setState({
+      visible: true,
+      formlist: getChartOptionForm(plot, columns, type)
+    })
+  }
+
+  onClose = (type) => {
+    if (type !== 'submit') {
+      this.setState({
+        visible: false
+      })
+      return
+    }
+
+    this.props.form.validateFieldsAndScroll((err, values) => {
+      if (!err) {
+        this.setState({
+          visible: false
+        })
+        this.props.plotchange(values)
+      }
+    })
+  }
+
+  getFields() {
+    const { formlist } = this.state
+    const { getFieldDecorator } = this.props.form
+    const fields = []
+
+    if (!formlist) {
+      return fields
+    }
+
+    formlist.forEach((item, index) => {
+      if (item.hidden) return
+      
+      if (item.type === 'text') { // 鏂囨湰鎼滅储
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  }
+                ]
+              })(<Input placeholder="" autoComplete="off" disabled={item.readonly}/>)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'number') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  }
+                ]
+              })(<InputNumber min={item.min} max={item.max} precision={item.decimal} />)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'select') { // 涓嬫媺鎼滅储
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <Select mode={item.multi ? 'multiple' : ''}>
+                  {item.options.map((option, index) =>
+                    <Select.Option key={index} value={option.field}>
+                      {option.label}
+                    </Select.Option>
+                  )}
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'radio') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <Radio.Group>
+                  {item.options.map(option => {
+                    return (
+                      <Radio key={option.value} value={option.value}>{option.text}</Radio>
+                    )
+                  })}
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      }
+    })
+    return fields
+  }
+
+  render() {
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 6 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 18 }
+      }
+    }
+
+    return (
+      <div className="line-chart-drawer-form">
+        <Icon type="edit" onClick={this.showDrawer} />
+        <Drawer
+          title="鍥捐〃缂栬緫"
+          className="chart-drawer-form"
+          width={720}
+          onClose={this.onClose}
+          visible={this.state.visible}
+          bodyStyle={{ paddingBottom: 80 }}
+        >
+          <Form {...formItemLayout}>
+            <Row gutter={16}>{this.getFields()}</Row>
+          </Form>
+          <div
+            style={{
+              position: 'absolute',
+              right: 0,
+              bottom: 0,
+              width: '100%',
+              borderTop: '1px solid #e9e9e9',
+              padding: '10px 16px',
+              background: '#fff',
+              textAlign: 'right',
+            }}
+          >
+            <Button onClick={this.onClose} style={{ marginRight: 8 }}>
+              鍙栨秷
+            </Button>
+            <Button onClick={() => this.onClose('submit')} type="primary">
+              鎻愪氦
+            </Button>
+          </div>
+        </Drawer>
+      </div>
+    );
+  }
+}
+
+export default Form.create()(LineChartDrawerForm)
\ No newline at end of file
diff --git a/src/templates/zshare/chartcompile/index.scss b/src/templates/zshare/chartcompile/index.scss
new file mode 100644
index 0000000..1f17fc6
--- /dev/null
+++ b/src/templates/zshare/chartcompile/index.scss
@@ -0,0 +1,31 @@
+.line-chart-drawer-form {
+  position: absolute;
+  right: 10px;
+
+  > .anticon-edit {
+    color: #1890ff;
+    font-size: 16px;
+    margin-right: 5px;
+  }
+}
+
+.chart-drawer-form {
+  .ant-drawer-body {
+    max-height: calc(100vh - 60px);
+    overflow-y: auto;
+  }
+  .ant-drawer-body::-webkit-scrollbar {
+    width: 7px;
+  }
+  .ant-drawer-body::-webkit-scrollbar-thumb {
+    border-radius: 5px;
+    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
+    background: rgba(0, 0, 0, 0.13);
+  }
+  .ant-drawer-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);
+  }
+}
diff --git a/src/templates/zshare/chartcomponent/index.jsx b/src/templates/zshare/chartcomponent/index.jsx
new file mode 100644
index 0000000..08359f5
--- /dev/null
+++ b/src/templates/zshare/chartcomponent/index.jsx
@@ -0,0 +1,437 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Chart } from '@antv/g2'
+import DataSet from '@antv/data-set'
+
+import ChartDrawerForm from '@/templates/zshare/chartcompile'
+import './index.scss'
+
+class LineChart extends Component {
+  static propTpyes = {
+    type: PropTypes.string,
+    dict: PropTypes.object,
+    plot: PropTypes.object,
+    columns: PropTypes.array,
+    plotchange: PropTypes.func
+  }
+
+  state = {
+    visible: true
+  }
+
+  componentDidMount () {
+    this.viewrender()
+  }
+
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    if (!is(fromJS(this.props.plot), fromJS(nextProps.plot))) {
+      this.setState({}, () => {
+        this.viewrender()
+      })
+    }
+  }
+
+  getdata = (X_axis, Y_axis) => {
+    const { type } = this.props
+    let data = []
+    let xdata = ['鍛ㄤ竴', '鍛ㄤ簩', '鍛ㄤ笁', '鍛ㄥ洓', '鍛ㄤ簲', '鍛ㄥ叚', '鍛ㄦ棩']
+    let point = 7
+
+    if (type === 'pie') {
+      xdata = ['浜嬩緥涓�', '浜嬩緥浜�', '浜嬩緥涓�', '浜嬩緥鍥�', '浜嬩緥浜�']
+      point = 5
+    }
+
+    for (let i = 0; i < point; i++) {
+      let item = {}
+
+      item[X_axis] = xdata[i]
+
+      if (typeof(Y_axis) === 'string') {
+        item[Y_axis] = Math.floor(Math.random() * 5 * (i + 1)) + i
+      } else {
+        Y_axis.forEach(y => {
+          item[y] = Math.floor(Math.random() * 5 * (i + 1)) + i
+        })
+      }
+
+      data.push(item)
+    }
+
+    return data
+  }
+
+  viewrender = () => {
+    const { type } = this.props
+
+    if (type === 'line') {
+      this.linerender()
+    } else if (type === 'bar') {
+      this.barrender()
+    } else if (type === 'pie') {
+      this.pierender()
+    }
+  }
+
+  linerender = () => {
+    const { plot, columns } = this.props
+
+    let transfield = {}
+    columns.forEach(col => {
+      if (col.field) {
+        transfield[col.field] = col.label
+      }
+    })
+    // const colors = ['#f49d37', '#f03838', '#35d1d1', '#5be56b', '#4e7af0', '#ebcc21']
+    let X_axis = plot.Xaxis || 'x'
+    let Y_axis = plot.Yaxis || ['y']
+
+    let data = this.getdata(X_axis, Y_axis)
+
+    const ds = new DataSet()
+    const dv = ds.createView().source(data)
+
+    dv.transform({
+      type: 'fold',
+      fields: [...Y_axis],
+      key: 'key', // key瀛楁
+      value: 'value', // value瀛楁
+      // retains: [], // 淇濈暀瀛楁闆嗭紝榛樿涓洪櫎 fields 浠ュ鐨勬墍鏈夊瓧娈�
+    })
+
+    if (plot.Xaxis) {
+      dv.transform({
+        type: 'map',
+        callback(row) {
+          row.key = transfield[row.key]
+          return row
+        },
+      })
+    }
+    
+    const chart = new Chart({
+      container: plot.uuid,
+      autoFit: true,
+      height: plot.height || 400
+    })
+
+    chart.data(dv.rows)
+
+    if (plot.coordinate !== 'polar') {
+      chart.scale(X_axis, {
+        range: [0, 1]
+      })
+    }
+    chart.scale('value', {
+      nice: true
+    })
+
+    if (!plot.legend || plot.legend === 'hidden') {
+      chart.legend(false)
+    } else {
+      chart.legend({
+        position: plot.legend
+      })
+    }
+
+    if (plot.tooltip !== 'true') {
+      chart.tooltip(false)
+    } else {
+      chart.tooltip({
+        shared: true
+      })
+    }
+
+    if (plot.transpose === 'true') {
+      chart.coordinate().transpose()
+    }
+
+    if (plot.coordinate === 'polar') {
+      chart.coordinate('polar', {
+        innerRadius: 0.1,
+        radius: 0.8
+      })
+    }
+
+    let _chart = chart
+      .line()
+      .position(`${X_axis}*value`)
+      .color('key')
+      .shape(plot.shape || 'smooth')
+
+    if (plot.label === 'true') {
+      _chart.label('value')
+    }
+
+    if (plot.point === 'true') {
+      chart
+        .point()
+        .position(`${X_axis}*value`)
+        .color('key')
+        .size(3)
+        .shape('circle')
+    }
+    
+    // chart.interaction('element-active') 
+    // chart.removeInteraction('legend-filter') // 鑷畾涔夊浘渚嬶紝绉婚櫎榛樿鐨勫垎绫诲浘渚嬬瓫閫変氦浜�
+    chart.render()
+  }
+
+  barrender = () => {
+    const { plot, columns } = this.props
+
+    let transfield = {}
+    columns.forEach(col => {
+      if (col.field) {
+        transfield[col.field] = col.label
+      }
+    })
+    let X_axis = plot.Xaxis || 'x'
+    let Y_axis = plot.Yaxis || ['y']
+    if (!plot.Yaxis && plot.modelId !== 'bar1') {
+      Y_axis = ['bar1', 'bar2']
+    }
+
+    let data = this.getdata(X_axis, Y_axis)
+
+    const ds = new DataSet()
+    const dv = ds.createView().source(data)
+
+    dv.transform({
+      type: 'fold',
+      fields: [...Y_axis],
+      key: 'key',
+      value: 'value'
+    })
+
+    if (plot.Xaxis) {
+      dv.transform({
+        type: 'map',
+        callback(row) {
+          row.key = transfield[row.key]
+          return row
+        },
+      })
+    }
+    
+    const chart = new Chart({
+      container: plot.uuid,
+      autoFit: true,
+      height: plot.height || 400
+    })
+
+    chart.data(dv.rows)
+
+    chart.scale('value', {
+      nice: true
+    })
+
+    if (!plot.legend || plot.legend === 'hidden') {
+      chart.legend(false)
+    } else {
+      chart.legend({
+        position: plot.legend
+      })
+    }
+
+    if (plot.tooltip !== 'true') {
+      chart.tooltip(false)
+    } else {
+      chart.tooltip({
+        shared: true
+      })
+    }
+
+    if (plot.transpose === 'true') {
+      chart.coordinate().transpose()
+    }
+
+    if (plot.coordinate === 'polar') {
+      chart.coordinate('polar', {
+        innerRadius: 0.1,
+        radius: 0.8
+      })
+    }
+
+    if (plot.adjust !== 'stack') {
+      chart
+        .interval()
+        .position(`${X_axis}*value`)
+        .color('key')
+        .adjust([
+          {
+            type: 'dodge',
+            marginRatio: 0
+          }
+        ])
+        .shape(plot.shape || 'rect')
+    } else if (plot.adjust === 'stack') {
+      chart
+        .interval()
+        .position(`${X_axis}*value`)
+        .color('key')
+        .adjust('stack')
+        .shape(plot.shape || 'rect')
+    }
+
+    chart.render()
+  }
+
+  pierender = () => {
+    const { plot, columns } = this.props
+
+    let transfield = {}
+    columns.forEach(col => {
+      if (col.field) {
+        transfield[col.field] = col.label
+      }
+    })
+    let X_axis = plot.Xaxis || 'x'
+    let Y_axis = plot.Yaxis || 'y'
+
+    let data = this.getdata(X_axis, Y_axis)
+
+    const ds = new DataSet()
+    const dv = ds.createView().source(data)
+
+    if (plot.pieshow !== 'value') {
+      dv.transform({
+        type: 'percent',
+        field: Y_axis,
+        dimension: X_axis,
+        as: 'percent'
+      })
+    }
+    
+    const chart = new Chart({
+      container: plot.uuid,
+      autoFit: true,
+      height: plot.height || 400
+    })
+
+    chart.data(dv.rows)
+
+    if (plot.pieshow !== 'value') {
+      chart.scale('percent', {
+        formatter: (val) => {
+          val = val * 100 + '%'
+          return val
+        }
+      })
+    }
+
+    chart.coordinate('theta', {
+      innerRadius: plot.shape === 'ring' ? 0.6 : 0,
+      radius: 0.75,
+    })
+
+    if (!plot.legend || plot.legend === 'hidden') {
+      chart.legend(false)
+    } else {
+      chart.legend({
+        position: plot.legend
+      })
+    }
+
+    if (plot.tooltip !== 'true') {
+      chart.tooltip(false)
+    } else {
+      chart.tooltip({
+        showTitle: false,
+        showMarkers: false
+      })
+    }
+
+    if (plot.pieshow !== 'value') {
+      let _chart = chart
+        .interval()
+        .adjust('stack')
+        .position('percent')
+        .color(X_axis)
+        .tooltip(X_axis + '*percent', (item, percent) => {
+          percent = (percent * 100).toFixed(2) + '%'
+          return {
+            name: item,
+            value: percent
+          }
+        })
+
+      if (plot.label === 'true') {
+        let setting = {
+          content: (data) => {
+            return `${data[X_axis]}: ${(data.percent * 100).toFixed(2)}%`
+          }
+        }
+
+        if (plot.labelLayout === 'overlap') {
+          setting.type = 'pie'
+          setting.layout = {
+            type: 'overlap'
+          }
+          setting.offset = 0
+          // setting.style = {
+          //   textAlign: 'center',
+          //   fontSize: 12,
+          //   fill: '#535353'
+          // }
+        }
+
+        _chart.label('percent', setting)
+      }
+      
+    } else {
+      let _chart = chart
+        .interval()
+        .adjust('stack')
+        .position(Y_axis)
+        .color(X_axis)
+        .tooltip(X_axis + '*' + Y_axis, (item, value) => {
+          return {
+            name: item,
+            value: value
+          }
+        })
+
+      if (plot.label === 'true') {
+        let setting = {
+          content: (data) => {
+            return `${data[X_axis]}: ${data[Y_axis]}`
+          }
+        }
+
+        if (plot.labelLayout === 'overlap') {
+          setting.type = 'pie'
+          setting.layout = {
+            type: 'overlap'
+          }
+          setting.offset = 0
+        }
+
+        _chart.label(Y_axis, setting)
+      }
+    }
+    
+    chart.render()
+  }
+
+  plotChange = (values) => {
+    const { plot } = this.props
+
+    this.props.plotchange({...plot, ...values})
+  }
+
+  render() {
+    const { plot, type } = this.props
+
+    return (
+      <div className="line-chart-edit-box" style={{minHeight: plot.height ? plot.height + 50 : 450}}>
+        <p className="chart-title">{plot.title}</p>
+        <ChartDrawerForm type={type} columns={this.props.columns} dict={this.props.dict} plot={plot} plotchange={this.plotChange} />
+        <div className="canvas" id={plot.uuid}></div>
+      </div>
+    )
+  }
+}
+
+export default LineChart
\ No newline at end of file
diff --git a/src/templates/zshare/chartcomponent/index.scss b/src/templates/zshare/chartcomponent/index.scss
new file mode 100644
index 0000000..cc0be8c
--- /dev/null
+++ b/src/templates/zshare/chartcomponent/index.scss
@@ -0,0 +1,7 @@
+.line-chart-edit-box {
+  margin-bottom: 30px;
+  
+  .canvas {
+    margin: 0 40px;
+  }
+}
diff --git a/src/templates/zshare/chartform/index.jsx b/src/templates/zshare/chartform/index.jsx
new file mode 100644
index 0000000..0d0c26d
--- /dev/null
+++ b/src/templates/zshare/chartform/index.jsx
@@ -0,0 +1,379 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Input, Select, InputNumber, Radio, Tooltip, Icon } from 'antd'
+
+import { formRule } from '@/utils/option.js'
+import line1 from '@/assets/img/line1.png'
+import line2 from '@/assets/img/line2.png'
+import line3 from '@/assets/img/line3.png'
+import line4 from '@/assets/img/line4.png'
+import bar1 from '@/assets/img/bar1.png'
+import bar2 from '@/assets/img/bar2.png'
+import bar3 from '@/assets/img/bar3.png'
+import bar4 from '@/assets/img/bar4.png'
+import pie1 from '@/assets/img/pie1.png'
+import pie2 from '@/assets/img/pie2.png'
+import './index.scss'
+
+const syslegends = {
+  line: [
+    {
+      uuid: 'line1',
+      url: line1,
+      options: {
+        shape: 'line',
+        coordinate: 'angle'
+      }
+    },
+    {
+      uuid: 'line2',
+      url: line2,
+      options: {
+        shape: 'smooth',
+        coordinate: 'angle'
+      }
+    },
+    {
+      uuid: 'line3',
+      url: line3,
+      options: {
+        shape: 'hv',
+        coordinate: 'angle'
+      }
+    },
+    {
+      uuid: 'line4',
+      url: line4,
+      options: {
+        shape: 'smooth',
+        coordinate: 'polar'
+      }
+    }
+  ],
+  bar: [
+    {
+      uuid: 'bar1',
+      url: bar1,
+      options: {
+        shape: 'rect',
+        adjust: 'dodge',
+        transpose: 'false'
+      }
+    },
+    {
+      uuid: 'bar2',
+      url: bar2,
+      options: {
+        shape: 'rect',
+        adjust: 'dodge',
+        transpose: 'false'
+      }
+    },
+    {
+      uuid: 'bar3',
+      url: bar3,
+      options: {
+        shape: 'rect',
+        adjust: 'stack',
+        transpose: 'false'
+      }
+    },
+    {
+      uuid: 'bar4',
+      url: bar4,
+      options: {
+        shape: 'rect',
+        adjust: 'dodge',
+        transpose: 'true'
+      }
+    }
+  ],
+  pie: [
+    {
+      uuid: 'pie1',
+      url: pie1,
+      options: {
+        shape: 'pie'
+      }
+    },
+    {
+      uuid: 'pie2',
+      url: pie2,
+      options: {
+        shape: 'ring'
+      }
+    }
+  ]
+}
+
+class ChartForm extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,     // 瀛楀吀椤�
+    MenuID: PropTypes.any,
+    formlist: PropTypes.any,
+    card: PropTypes.any,
+    inputSubmit: PropTypes.any  // 鍥炶溅鎻愪氦浜嬩欢
+  }
+
+  state = {
+    formlist: null,
+    legends: null,
+    selectlegend: null
+  }
+
+  UNSAFE_componentWillMount () {
+    const { card } = this.props
+
+    let _type = card.chartType || 'line'
+    let _legends = null
+    let _selectlegend = null
+
+    if (_type === 'line' || _type === 'bar' || _type === 'line') {
+      _legends = syslegends[_type]
+      _selectlegend = _legends.filter(item => item.uuid === card.modelId)[0]
+
+      if (!_selectlegend) {
+        _selectlegend = _legends[0]
+      }
+    }
+
+    this.setState({
+      legends: _legends,
+      selectlegend: _selectlegend
+    })
+  }
+
+  componentDidMount () {
+    const { card } = this.props
+
+    if (!card.chartType) {
+      try {
+        let _form = document.getElementById('title')
+        _form.select()
+      } catch {
+        console.warn('琛ㄥ崟focus澶辫触锛�')
+      }
+    }
+  }
+
+  handleSubmit = (e) => {
+    e.preventDefault()
+
+    if (this.props.inputSubmit) {
+      this.props.inputSubmit()
+    }
+  }
+
+  typeChange = (key, value) => {
+    if (key === 'chartType') {
+      this.setState({
+        legends: syslegends[value] || null,
+        selectlegend: syslegends[value][0]
+      })
+    }
+  }
+
+  changeSelectLegend = (item) => {
+    this.setState({
+      selectlegend: item
+    })
+  }
+
+  getFields() {
+    const { getFieldDecorator } = this.props.form
+    const fields = []
+    this.props.formlist.forEach((item, index) => {
+      if (item.hidden) return
+      
+      if (item.type === 'text') { // 鏂囨湰鎼滅储
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" overlayClassName={item.tooltipClass} title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || '',
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  },
+                  {
+                    max: formRule.input.max,
+                    message: formRule.input.message
+                  }
+                ]
+              })(<Input placeholder="" autoComplete="off" disabled={item.readonly} onPressEnter={this.handleSubmit} />)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'number') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" overlayClassName={item.tooltipClass} title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  }
+                ]
+              })(<InputNumber min={item.min} max={item.max} precision={item.decimal} />)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'select') { // 涓嬫媺鎼滅储
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || '',
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <Select
+                  showSearch
+                  disabled={!!item.readonly}
+                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                  onChange={(value) => {this.typeChange(item.key, value)}}
+                  getPopupContainer={() => document.getElementById('chartwinter')}
+                >
+                  {item.options.map((option, index) =>
+                    <Select.Option id={`${index}`} title={option.text} key={`${index}`} value={option.value}>
+                      {option.text}
+                    </Select.Option>
+                  )}
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'radio') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <Radio.Group>
+                  {
+                    item.options.map(option => {
+                      return (
+                        <Radio key={option.value} value={option.value}>{option.text}</Radio>
+                      )
+                    })
+                  }
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'multiselect') { // 澶氶��
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || []
+              })(
+                <Select
+                  showSearch
+                  mode="multiple"
+                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                >
+                  {item.options.map((option, i) =>
+                    <Select.Option id={i} key={i} value={option.value}>{option.text}</Select.Option>
+                  )}
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      }
+    })
+    return fields
+  }
+
+  handleConfirm = () => {
+    const { selectlegend } = this.state
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          let result = {...this.props.card, ...values}
+          
+          let icons = {
+            table: 'table',
+            line: 'line-chart',
+            bar: 'bar-chart',
+            pie: 'pie-chart'
+          }
+
+          if (selectlegend && this.props.card.modelId !== selectlegend.uuid) {
+            result = {...result, ...selectlegend.options}
+          }
+
+          if (selectlegend) {
+            result.modelId = selectlegend.uuid
+          }
+
+          if (result.chartType !== 'pie' && result.Yaxis && typeof(result.Yaxis) === 'string') {
+            result.Yaxis = [result.Yaxis]
+          } else if (result.chartType === 'pie' && result.Yaxis && typeof(result.Yaxis) === 'object') {
+            result.Yaxis = result.Yaxis[0] || ''
+          }
+
+          result.icon = icons[result.chartType]
+
+          resolve(result)
+        } else {
+          reject(err)
+        }
+      })
+    })
+  }
+
+  render() {
+    const { legends, selectlegend } = this.state
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 6 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 18 }
+      }
+    }
+    return (
+      <Form {...formItemLayout} className="chart-edit-form" id="chartwinter">
+        <Row gutter={24}>{this.getFields()}</Row>
+        {legends ? <Row gutter={24} className="chart-model-image">
+          {legends.map(item => <Col span={6} key={item.uuid}>
+            <img onClick={() => this.changeSelectLegend(item)} src={item.url} className={selectlegend.uuid === item.uuid ? 'active' : ''} alt=""/>
+          </Col>)}
+        </Row> : null}
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(ChartForm)
\ No newline at end of file
diff --git a/src/templates/zshare/chartform/index.scss b/src/templates/zshare/chartform/index.scss
new file mode 100644
index 0000000..a1778ca
--- /dev/null
+++ b/src/templates/zshare/chartform/index.scss
@@ -0,0 +1,25 @@
+.chart-edit-form {
+  min-height: 190px;
+  .ant-form-item {
+    .ant-input-number {
+      width: 100%;
+    }
+  }
+  .anticon-question-circle {
+    color: #c49f47;
+    position: relative;
+    left: -3px;
+  }
+  .chart-model-image {
+    img {
+      max-width: 100%;
+      cursor: pointer;
+      border: 1px solid #ebedf0;
+      transition: all .3s;
+    }
+    img.active {
+      background-color: rgba(135,59,244,.1);
+      border-color: #873bf4;
+    }
+  }
+}
diff --git a/src/templates/zshare/createinterface/index.jsx b/src/templates/zshare/createinterface/index.jsx
index 1b3d1e2..568bd34 100644
--- a/src/templates/zshare/createinterface/index.jsx
+++ b/src/templates/zshare/createinterface/index.jsx
@@ -23,11 +23,17 @@
     btn: null
   }
 
+  /**
+   * @description 瑙﹀彂鍒涘缓璇绘暟鎹帴鍙�
+   * @param { object } menu    鑿滃崟绫诲瀷锛堜笁绾ц彍鍗曟垨鏍囩椤碉級銆佽彍鍗旾D銆佽彍鍗曞弬鏁般�佽彍鍗曞悕绉�
+   * @param { object } config  鑿滃崟閰嶇疆淇℃伅
+   */
   triggerOutInterface = (menu, config) => {
     let _search = []
     let _index = 1
 
     if (menu.type !== 'main') {
+      // 瀛愯〃椤甸潰澧炲姞BID瀛楁锛屾暟鎹簮涓娇鐢ㄤ簡@BID@鏃讹紝BID绫诲瀷涓哄繀浼�
       if (config.setting.dataresource && /@BID@/ig.test(config.setting.dataresource)) {
         _search.push(`select 'BID' as searchfield,'BID' as label,'0' as Sort,'' as defaultvalue,'required' as DefaultType`)
       } else {
@@ -283,7 +289,26 @@
     })
   }
 
+  /**
+   * @description 瑙﹀彂鍒涘缓鍐欏叆鎺ュ彛锛堟寜閽級
+   */
   triggerInInterface = (btn, config, menu) => {
+    if (!['pop', 'exec', 'prompt'].includes(btn.OpenType) || btn.funcType || btn.intertype !== 'inner' || btn.innerFunc ) {
+      notification.warning({
+        top: 92,
+        message: '鎵撳紑鏂瑰紡涓� 寮圭獥锛堣〃鍗曪級銆佹彁绀烘鎴栫洿鎺ユ墽琛岋紝涓斾娇鐢ㄧ郴缁熷嚱鏁版椂锛屾墠鍙互鍒涘缓鎺ュ彛锛�',
+        duration: 5
+      })
+      return
+    } else if (btn.Ot === 'requiredOnce') {
+      notification.warning({
+        top: 92,
+        message: '澶氳鎷兼帴鏃讹紝涓嶆敮鎸佸垱寤烘帴鍙o紒',
+        duration: 5
+      })
+      return
+    }
+
     let param = {
       func: 's_get_para_for_in',
       Menuid: btn.uuid,
@@ -343,6 +368,9 @@
     })
   }
 
+  /**
+   * @description 鎵ц鎺ュ彛鍒涘缓
+   */
   createBtnInterfaceExec = (param, config, btn) => {
     let formlist = []
     let receipt = param.Return === 'Y'
@@ -448,9 +476,14 @@
       })
 
       if (param.menuType !== 'main' && !_keys.includes('bid')) {
+        _keys.push('bid')
         param.Ltexttableparam.unshift(`select 'BID' as searchfield,'BID' as label,'0' as Sort,'nvarchar(50)' as fieldtype,'required' as requiredtype,'' as defaultvalue`)
       }
 
+      if (btn.Ot !== 'notRequired' && !_keys.includes(config.setting.primaryKey.toLowerCase())) {
+        param.Ltexttableparam.unshift(`select '${config.setting.primaryKey}' as searchfield,'${config.setting.primaryKey}' as label,'1' as Sort,'nvarchar(50)' as fieldtype,'required' as requiredtype,'' as defaultvalue`)
+      }
+
       param.Ltexttableparam = param.Ltexttableparam.join(' union all ')
       
       if (receipt) {
diff --git a/src/templates/zshare/editcomponent/index.jsx b/src/templates/zshare/editcomponent/index.jsx
index cf54d8d..28f010d 100644
--- a/src/templates/zshare/editcomponent/index.jsx
+++ b/src/templates/zshare/editcomponent/index.jsx
@@ -141,7 +141,15 @@
         }, () => {
           this.props.refresh({
             type: 'paste',
-            copyType: 'action',
+            content: res
+          })
+        })
+      } else if (res.copyType === 'search') {
+        this.setState({
+          pasteVisible: false
+        }, () => {
+          this.props.refresh({
+            type: 'paste',
             content: res
           })
         })
@@ -160,8 +168,7 @@
         }, () => {
           this.props.refresh({
             type: 'paste',
-            copyType: 'columns',
-            config: {...config, columns: res.columns}
+            content: res
           })
         })
       } else {
@@ -179,7 +186,7 @@
       <Menu onClick={this.handleMenuClick}>
         <Menu.Item key="thaw"><Icon type="unlock" />{this.props.dict['header.form.thawbutton']}</Menu.Item>
         <Menu.Item key="paste"><Icon type="snippets" />{this.props.dict['header.form.paste']}</Menu.Item>
-        <Menu.Item key="replace"><Icon type="retweet" />鏇挎崲</Menu.Item>
+        {/* <Menu.Item key="replace"><Icon type="retweet" />鏇挎崲</Menu.Item> */}
       </Menu>
     )
 
@@ -193,7 +200,7 @@
         {/* 瑙e喕鎸夐挳妯℃�佹 */}
         <Modal
           title={this.props.dict['header.form.thawbutton']}
-          okText={this.props.dict['header.confirm']}
+          okText={this.props.dict['model.confirm']}
           cancelText={this.props.dict['header.cancel']}
           visible={this.state.thawVisible}
           onOk={this.thawBtnSubmit}
diff --git a/src/templates/zshare/exceleditable/index.jsx b/src/templates/zshare/exceleditable/index.jsx
index 332fe1b..0b5ceea 100644
--- a/src/templates/zshare/exceleditable/index.jsx
+++ b/src/templates/zshare/exceleditable/index.jsx
@@ -188,7 +188,7 @@
               <span className="operation-btn" title={props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
               <Popconfirm
                 title={props.dict['header.form.query.delete']}
-                okText={props.dict['header.confirm']}
+                okText={props.dict['model.confirm']}
                 cancelText={props.dict['header.cancel']}
                 onConfirm={() => this.handleDelete(record.key)
               }>
diff --git a/src/templates/zshare/formconfig.jsx b/src/templates/zshare/formconfig.jsx
index d72cf10..371490a 100644
--- a/src/templates/zshare/formconfig.jsx
+++ b/src/templates/zshare/formconfig.jsx
@@ -1,5 +1,5 @@
-import zhCN from '@/locales/zh-CN/comtable.js'
-import enUS from '@/locales/en-US/comtable.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
 
 const Formdict = localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
 
@@ -252,8 +252,55 @@
  * @param {*} functip        鐢熸垚瀛樺偍杩囩▼鎻愮ず
  * @param {*} config         椤甸潰閰嶇疆
  * @param {*} permFuncField  瀛樺偍杩囩▼鍙敤鐨勫紑濮嬪瓧娈�
+ * @param {*} type           鎸夐挳绫诲瀷锛岀敤浜庡尯鍒嗗彲閫夌殑鎵撳紑鏂瑰紡
  */
-export function getActionForm (card, functip, config, permFuncField) {
+export function getActionForm (card, functip, config, permFuncField, type) {
+  let opentypes = [
+    {
+      value: 'pop',
+      text: Formdict['header.form.popform']
+    }, {
+      value: 'prompt',
+      text: Formdict['header.form.prompt']
+    }, {
+      value: 'exec',
+      text: Formdict['header.form.exec']
+    }, {
+      value: 'excelIn',
+      text: Formdict['header.form.excelIn']
+    }, {
+      value: 'excelOut',
+      text: Formdict['header.form.excelOut']
+    }, {
+      value: 'popview',
+      text: Formdict['header.form.popview']
+    }
+  ]
+
+  if (type === 'subtable') {
+    opentypes.push({
+      value: 'funcbutton',
+      text: Formdict['header.form.funcbutton']
+    })
+  } else {
+    opentypes.push({
+      value: 'tab',
+      text: Formdict['header.form.tab']
+    }, {
+      value: 'blank',
+      text: Formdict['header.form.blank']
+    }, {
+      value: 'innerpage',
+      text: Formdict['header.form.newpage.inner']
+    }, {
+      value: 'outerpage',
+      text: Formdict['header.form.newpage.outer']
+    }, {
+      value: 'funcbutton',
+      text: Formdict['header.form.funcbutton']
+    })
+  }
+
   return [
     {
       type: 'text',
@@ -269,40 +316,7 @@
       label: Formdict['header.form.openType'],
       initVal: card.OpenType,
       required: true,
-      options: [{
-        value: 'pop',
-        text: Formdict['header.form.popform']
-      }, {
-        value: 'prompt',
-        text: Formdict['header.form.prompt']
-      }, {
-        value: 'exec',
-        text: Formdict['header.form.exec']
-      }, {
-        value: 'excelIn',
-        text: Formdict['header.form.excelIn']
-      }, {
-        value: 'excelOut',
-        text: Formdict['header.form.excelOut']
-      }, {
-        value: 'popview',
-        text: Formdict['header.form.popview']
-      }, {
-        value: 'tab',
-        text: Formdict['header.form.tab']
-      }, {
-        value: 'blank',
-        text: Formdict['header.form.blank']
-      }, {
-        value: 'innerpage',
-        text: Formdict['header.form.newpage.inner']
-      }, {
-        value: 'outerpage',
-        text: Formdict['header.form.newpage.outer']
-      }, {
-        value: 'funcbutton',
-        text: Formdict['header.form.funcbutton']
-      }]
+      options: opentypes
     },
     {
       type: 'select',
@@ -871,6 +885,295 @@
 }
 
 /**
+ * @description 鑾峰彇鍥捐〃瑙嗗浘澶栭儴閰嶇疆琛ㄥ崟
+ * @param {*} card
+ */
+export function getChartViewForm (card, roleList = []) {
+  let _charts = [{
+    value: 'line',
+    text: '鎶樼嚎鍥�'
+  }, {
+    value: 'bar',
+    text: '鏌辩姸鍥�'
+  }, {
+    value: 'pie',
+    text: '楗煎浘'
+  }]
+
+  if (card.chartType === 'table') {
+    _charts = [{
+      value: 'table',
+      text: '琛ㄦ牸'
+    }]
+  }
+
+  return [
+    {
+      type: 'text',
+      key: 'title',
+      label: Formdict['header.form.title'],
+      initVal: card.title,
+      required: false
+    },
+    {
+      type: 'select',
+      key: 'chartType',
+      label: '鍥捐〃绫诲瀷',
+      initVal: card.chartType,
+      required: true,
+      readonly: card.chartType === 'table',
+      options: _charts
+    },
+    {
+      type: 'number',
+      key: 'height',
+      min: 100,
+      max: 1000,
+      decimal: 0,
+      label: '楂樺害',
+      initVal: card.height || 400,
+      required: true
+    },
+    {
+      type: 'number',
+      key: 'width',
+      min: 1,
+      max: 24,
+      decimal: 0,
+      label: '瀹藉害',
+      tooltip: '姣忚绛夊垎涓�24鍒楋紝24鍗充负100%銆�',
+      initVal: card.width || 24,
+      required: true
+    },
+    {
+      type: 'radio',
+      key: 'Hide',
+      label: Formdict['header.form.Hide'],
+      initVal: card.Hide,
+      required: true,
+      options: [{
+        value: 'true',
+        text: Formdict['header.form.true']
+      }, {
+        value: 'false',
+        text: Formdict['header.form.false']
+      }]
+    },
+    {
+      type: 'multiselect',
+      key: 'blacklist',
+      label: Formdict['header.form.blacklist'],
+      initVal: card.blacklist || [],
+      required: false,
+      options: roleList
+    }
+  ]
+}
+
+/**
+ * @description 鑾峰彇鍥捐〃瑙嗗浘閰嶇疆琛ㄥ崟
+ * @param {*} card
+ */
+export function getChartOptionForm (card, columns, type) {
+  let shapes = []
+
+  if (type === 'line') {
+    shapes = [
+      { field: 'smooth', label: 'smooth' },
+      { field: 'line', label: 'line' },
+      { field: 'dot', label: 'dot' },
+      { field: 'dash', label: 'dash' },
+      { field: 'hv', label: 'hv' },
+      { field: 'vh', label: 'vh' },
+      { field: 'hvh', label: 'hvh' },
+      { field: 'vhv', label: 'vhv' }
+    ]
+  } else if (type === 'bar') {
+    shapes = [
+      { field: 'rect', label: 'rect' },
+      { field: 'hollow-rect', label: 'hollow-rect' },
+      { field: 'line', label: 'line' },
+      { field: 'tick', label: 'tick' },
+      { field: 'funnel', label: 'funnel' },
+      { field: 'pyramid', label: 'pyramid' }
+    ]
+  } else if (type === 'pie') {
+    shapes = [
+      { field: 'pie', label: '楗煎浘' },
+      { field: 'ring', label: '鐜浘' }
+    ]
+  }
+
+  return [
+    {
+      type: 'select',
+      key: 'Xaxis',
+      label: type === 'pie' ? 'Text' : 'X-杞�',
+      initVal: card.Xaxis || '',
+      required: true,
+      options: columns.filter(col => col.type === 'text')
+    },
+    {
+      type: 'select',
+      key: 'Yaxis',
+      label: type === 'pie' ? 'Value' : 'Y-杞�',
+      initVal: type === 'pie' ? card.Yaxis || '' : card.Yaxis || [],
+      multi: type !== 'pie',
+      required: true,
+      options: columns.filter(col => col.type === 'number')
+    },
+    {
+      type: 'select',
+      key: 'legend',
+      label: '鍥句緥浣嶇疆',
+      initVal: card.legend || 'bottom',
+      required: false,
+      options: [
+        { field: 'top', label: 'top' },
+        { field: 'top-left', label: 'top-left' },
+        { field: 'top-right', label: 'top-right' },
+        { field: 'right', label: 'right' },
+        { field: 'right-top', label: 'right-top' },
+        { field: 'right-bottom', label: 'right-bottom' },
+        { field: 'left', label: 'left' },
+        { field: 'left-top', label: 'left-top' },
+        { field: 'left-bottom', label: 'left-bottom' },
+        { field: 'bottom', label: 'bottom' },
+        { field: 'bottom-left', label: 'bottom-left' },
+        { field: 'bottom-right', label: 'bottom-right' },
+        { field: 'hidden', label: 'hidden' }
+      ]
+    },
+    {
+      type: 'select',
+      key: 'shape',
+      label: '褰㈢姸',
+      initVal: card.shape || (shapes[0] && shapes[0].field),
+      required: false,
+      hidden: !['line', 'bar', 'pie'].includes(type),
+      options: shapes
+    },
+    {
+      type: 'radio',
+      key: 'tooltip',
+      label: '鎻愮ず淇℃伅',
+      initVal: card.tooltip || 'true',
+      required: false,
+      options: [{
+        value: 'true',
+        text: '鏄剧ず'
+      }, {
+        value: 'false',
+        text: '闅愯棌'
+      }]
+    },
+    {
+      type: 'radio',
+      key: 'coordinate',
+      label: '鍧愭爣',
+      initVal: card.coordinate || 'angle',
+      required: false,
+      hidden: !['line', 'bar'].includes(type),
+      options: [{
+        value: 'angle',
+        text: '浜岀淮鍧愭爣'
+      }, {
+        value: 'polar',
+        text: '鏋佸潗鏍�'
+      }]
+    },
+    {
+      type: 'radio',
+      key: 'point',
+      label: '鐐瑰浘',
+      initVal: card.point || 'false',
+      required: false,
+      hidden: !['line'].includes(type),
+      options: [{
+        value: 'true',
+        text: '鏄剧ず'
+      }, {
+        value: 'false',
+        text: '闅愯棌'
+      }]
+    },
+    {
+      type: 'radio',
+      key: 'transpose',
+      label: '鍙樻崲',
+      initVal: card.transpose || 'false',
+      required: false,
+      hidden: !['line', 'bar'].includes(type),
+      options: [{
+        value: 'true',
+        text: Formdict['header.form.true']
+      }, {
+        value: 'false',
+        text: Formdict['header.form.false']
+      }]
+    },
+    {
+      type: 'radio',
+      key: 'pieshow',
+      label: '鏄剧ず鍊�',
+      initVal: card.pieshow || 'percent',
+      required: false,
+      hidden: !['pie'].includes(type),
+      options: [{
+        value: 'percent',
+        text: '鐧惧垎姣�'
+      }, {
+        value: 'value',
+        text: '鏁板��'
+      }]
+    },
+    {
+      type: 'radio',
+      key: 'label',
+      label: '鏂囨湰鏍囩',
+      initVal: card.label || (type === 'pie' ? 'true' : 'false'),
+      required: false,
+      hidden: !['pie', 'line'].includes(type),
+      options: [{
+        value: 'true',
+        text: '鏄剧ず'
+      }, {
+        value: 'false',
+        text: '闅愯棌'
+      }]
+    }, {
+      type: 'radio',
+      key: 'labelLayout',
+      label: '鏍囩甯冨眬',
+      initVal: card.labelLayout || 'normal',
+      required: false,
+      hidden: !['pie'].includes(type),
+      options: [{
+        value: 'normal',
+        text: '甯歌'
+      }, {
+        value: 'overlap',
+        text: '闃查噸鍙�'
+      }]
+    }, {
+      type: 'radio',
+      key: 'adjust',
+      label: '澶氭煴鎺掑垪',
+      initVal: card.adjust || 'dodge',
+      required: false,
+      hidden: !['bar'].includes(type),
+      options: [{
+        value: 'dodge',
+        text: '鍒嗙粍'
+      }, {
+        value: 'stack',
+        text: '鍫嗗彔'
+      }]
+    }
+  ]
+}
+
+/**
  * @description 鑾峰彇琛ㄥ崟閰嶇疆淇℃伅
  * @param {*} card 
  * @param {*} inputfields 
diff --git a/src/templates/zshare/modaleditable/index.jsx b/src/templates/zshare/modaleditable/index.jsx
index d2104a8..90119fb 100644
--- a/src/templates/zshare/modaleditable/index.jsx
+++ b/src/templates/zshare/modaleditable/index.jsx
@@ -158,7 +158,7 @@
               <span className="operation-btn" title={props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
               <Popconfirm
                 title={props.dict['header.form.query.delete']}
-                okText={props.dict['header.confirm']}
+                okText={props.dict['model.confirm']}
                 cancelText={props.dict['header.cancel']}
                 onConfirm={() => this.handleDelete(record.key)
               }>
@@ -364,7 +364,7 @@
               <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
               <Popconfirm
                 title={this.props.dict['header.form.query.delete']}
-                okText={this.props.dict['header.confirm']}
+                okText={this.props.dict['model.confirm']}
                 cancelText={this.props.dict['header.cancel']}
                 onConfirm={() => this.handleDelete(record.key)
               }>
diff --git a/src/templates/zshare/pasteform/index.jsx b/src/templates/zshare/pasteform/index.jsx
index fcb82db..eb1632a 100644
--- a/src/templates/zshare/pasteform/index.jsx
+++ b/src/templates/zshare/pasteform/index.jsx
@@ -1,6 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { Form, Row, Col, Input, notification } from 'antd'
+import Utils from '@/utils/utils.js'
 import './index.scss'
 
 const { TextArea } = Input
@@ -39,6 +40,10 @@
             _config = ''
           }
 
+          if (_config && _config.uuid) { // 姣忔绮樿创鏃舵洿鏂癐D锛岄槻姝㈤噸澶嶇矘璐存椂id閲嶅
+            _config.uuid = Utils.getuuid()
+          }
+
           if (_config) {
             resolve(_config)
           }
diff --git a/src/templates/zshare/tabdragelement/card.jsx b/src/templates/zshare/tabdragelement/card.jsx
index 4ebb9de..81ec448 100644
--- a/src/templates/zshare/tabdragelement/card.jsx
+++ b/src/templates/zshare/tabdragelement/card.jsx
@@ -25,7 +25,7 @@
         const { index: overIndex } = findCard(id)
         moveCard(draggedId, overIndex)
       }
-    },
+    }
   })
 
   const doubleClick = () => {
diff --git a/src/templates/zshare/transferform/index.scss b/src/templates/zshare/transferform/index.scss
index cedc47b..1ebb78b 100644
--- a/src/templates/zshare/transferform/index.scss
+++ b/src/templates/zshare/transferform/index.scss
@@ -8,7 +8,9 @@
   }
   .ant-transfer-operation + .ant-transfer-list {
     .ant-transfer-list-content-item {
-      margin-right: 50px;
+      padding-right: 50px;
+      position: relative;
+      
       i {
         display: inline-block;
       }
diff --git a/src/templates/zshare/verifycard/customform/index.jsx b/src/templates/zshare/verifycard/customform/index.jsx
index eec4967..0065c37 100644
--- a/src/templates/zshare/verifycard/customform/index.jsx
+++ b/src/templates/zshare/verifycard/customform/index.jsx
@@ -12,6 +12,7 @@
 class CustomForm extends Component {
   static propTpyes = {
     dict: PropTypes.object,         // 瀛楀吀椤�
+    btn: PropTypes.object,          // 鎸夐挳
     usefulfields: PropTypes.string, // 鍙敤瀛楁
     initsql: PropTypes.string,      // 鍙敤瀛楁
     customChange: PropTypes.func    // 琛ㄥ崟
@@ -120,7 +121,7 @@
   }
 
   render() {
-    const { usefulfields } = this.props
+    const { usefulfields, btn } = this.props
     const { getFieldDecorator } = this.props.form
     const formItemLayout = {
       labelCol: {
@@ -157,6 +158,9 @@
             <Button onClick={this.handleConfirm} loading={this.state.loading} className="mk-green">
               淇濆瓨
             </Button>
+            {btn.sql ? <div style={{marginTop: '31px'}}>
+              琛ㄥ悕:  <div style={{wordBreak: 'break-all'}}>{btn.sql}</div>
+            </div> : null}
           </Col>
           <Col span={7}>
             <Form.Item label={'缁撴灉澶勭悊'}>
diff --git a/src/templates/zshare/verifycard/customscript/index.jsx b/src/templates/zshare/verifycard/customscript/index.jsx
index 98977c0..b1fabe2 100644
--- a/src/templates/zshare/verifycard/customscript/index.jsx
+++ b/src/templates/zshare/verifycard/customscript/index.jsx
@@ -1,6 +1,6 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
-import { Form, Row, Col, Input, Button, notification, Modal, Select, Tooltip, Icon, Radio } from 'antd'
+import { Form, Row, Col, Input, Button, notification, Modal, Menu, Tooltip, Icon, Radio, Dropdown } from 'antd'
 import moment from 'moment'
 
 import Utils from '@/utils/utils.js'
@@ -12,6 +12,7 @@
 class CustomForm extends Component {
   static propTpyes = {
     dict: PropTypes.object,         // 瀛楀吀椤�
+    btn: PropTypes.object,          // 鎸夐挳淇℃伅
     usefulfields: PropTypes.string, // 鍙敤瀛楁
     initsql: PropTypes.string,      // sql鍓嶇紑
     systemScripts: PropTypes.array, // 绯荤粺鑴氭湰
@@ -130,7 +131,11 @@
     })
   }
 
-  selectScript = (val, option) => {
+  selectScript = (e) => {
+    const { systemScripts } = this.props
+
+    let option = systemScripts[+e.key]
+
     let _sql = this.props.form.getFieldValue('sql')
     if (_sql) {
       _sql = _sql + ` 
@@ -139,10 +144,10 @@
     }
 
     _sql = _sql.replace(/\s{6}$/, '')
-    _sql = _sql + `/*${option.props.title}*/
+    _sql = _sql + `/*${option.name}*/
     `
     _sql = _sql.replace(/\s{4}$/, '')
-    _sql = _sql + val
+    _sql = _sql + option.value
 
     this.props.form.setFieldsValue({
       sql: _sql
@@ -150,7 +155,7 @@
   }
 
   render() {
-    const { usefulfields, systemScripts } = this.props
+    const { usefulfields, systemScripts, btn } = this.props
     const { getFieldDecorator } = this.props.form
     const formItemLayout = {
       labelCol: {
@@ -171,7 +176,7 @@
               {usefulfields}
             </Form.Item>
           </Col> : null}
-          <Col span={8}>
+          <Col span={8} style={{whiteSpace: 'nowrap'}}>
             <Form.Item style={{marginBottom: 0}} label={
               <Tooltip placement="bottomLeft" title={'鑷畾涔夎剼鏈笌榛樿sql浣嶇疆鍏崇郴銆�'}>
                 <Icon type="question-circle" style={{color: '#c49f47', marginRight: '5px'}} />
@@ -189,27 +194,29 @@
               )}
             </Form.Item>
           </Col>
-          <Col span={8}>
-            <Form.Item style={{marginBottom: 0}} label={
-              <Tooltip placement="bottomLeft" title={'浠庣郴缁熷嚱鏁伴泦涓�夋嫨闇�瑕佺殑鍑芥暟锛屽彲蹇�熸坊鍔犺嚦sql涓��'}>
-                <Icon type="question-circle" style={{color: '#c49f47', marginRight: '5px'}} />
-                蹇嵎娣诲姞
-              </Tooltip>
-            }>
-              <Select value="" onChange={this.selectScript}>
+          <Col span={4} style={{lineHeight: '40px', textAlign: 'center'}}>
+            <Dropdown trigger={['click']} overlayClassName="mk-normal-dropdown" overlay={
+              <Menu onClick={this.selectScript}>
                 {systemScripts.map((option, i) =>
-                  <Select.Option title={option.name} key={i} value={option.value}>
-                    {option.name}
-                  </Select.Option>
+                  <Menu.Item key={i}>{option.name}</Menu.Item>
                 )}
-              </Select>
-            </Form.Item>
+              </Menu>
+            }>
+              <span style={{color: '#1890ff', display: 'inline-block', cursor: 'pointer'}}>
+                蹇嵎娣诲姞 <Icon type="down" style={{marginRight: '5px'}} />
+              </span>
+            </Dropdown>
           </Col>
           <Col span={4} className="add">
             <Button onClick={this.handleConfirm} loading={this.state.loading} className="mk-green" style={{marginBottom: 15, marginLeft: 40}}>
               淇濆瓨
             </Button>
           </Col>
+          <Col span={8} style={{textAlign: 'right'}}>
+            {btn.sql ? <span style={{maxWidth: '100%', display: 'inline-block', position: 'relative', top: '20px', whiteSpace: 'nowrap', textOverflow: 'ellipsis', overflow: 'hidden'}}>
+              琛ㄥ悕:  {btn.sql}
+            </span> : null}
+          </Col>
           <Col span={24} className="sql">
             <Form.Item label={'sql'}>
               {getFieldDecorator('sql', {
diff --git a/src/templates/zshare/verifycard/index.jsx b/src/templates/zshare/verifycard/index.jsx
index 4bb5edf..0efe780 100644
--- a/src/templates/zshare/verifycard/index.jsx
+++ b/src/templates/zshare/verifycard/index.jsx
@@ -13,6 +13,7 @@
 import BillcodeForm from './billcodeform'
 import VoucherForm from './voucherform'
 import './index.scss'
+import { fromJS } from 'immutable';
 
 const { TabPane } = Tabs
 const { confirm } = Modal
@@ -23,7 +24,7 @@
     btnTab: PropTypes.any,     // 琛ㄥ崟鏍囩椤碉紙鎸夐挳锛夊弬鏁�
     config: PropTypes.any,     // 琛ㄥ崟鏍囩椤靛弬鏁�
     dict: PropTypes.object,    // 瀛楀吀椤�
-    card: PropTypes.object,
+    card: PropTypes.object,    // 鎸夐挳淇℃伅
     columns: PropTypes.array
   }
 
@@ -32,6 +33,7 @@
     verify: {},
     fields: [],
     usefulfields: '',
+    defaultsql: '',         // 榛樿Sql
     orderModular: [],
     orderModularDetail: [],
     voucher: [],
@@ -79,13 +81,13 @@
         dataIndex: 'operation',
         render: (text, record) =>
           (<div>
-            <span className="operation-btn" title={this.props.dict['header.edit']} onClick={() => this.handleEdit(record, 'unique')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
+            <span className="operation-btn" title={this.props.dict['model.edit']} onClick={() => this.handleEdit(record, 'unique')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
             <span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'unique', 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
             <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'unique', 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
             <span className="operation-btn" title={this.props.dict['header.form.status.change']} onClick={() => this.handleStatus(record, 'unique')} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
             <Popconfirm
               title={this.props.dict['header.form.query.delete']}
-              okText={this.props.dict['header.confirm']}
+              okText={this.props.dict['model.confirm']}
               cancelText={this.props.dict['header.cancel']}
               onConfirm={() => this.handleDelete(record, 'unique')
             }>
@@ -145,13 +147,13 @@
         dataIndex: 'operation',
         render: (text, record) =>
           (<div>
-            <span className="operation-btn" title={this.props.dict['header.edit']} onClick={() => this.handleEdit(record, 'contrast')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
+            <span className="operation-btn" title={this.props.dict['model.edit']} onClick={() => this.handleEdit(record, 'contrast')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
             <span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'contrast', 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
             <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'contrast', 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
             <span className="operation-btn" title={this.props.dict['header.form.status.change']} onClick={() => this.handleStatus(record, 'contrast')} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
             <Popconfirm
               title={this.props.dict['header.form.query.delete']}
-              okText={this.props.dict['header.confirm']}
+              okText={this.props.dict['model.confirm']}
               cancelText={this.props.dict['header.cancel']}
               onConfirm={() => this.handleDelete(record, 'contrast')
             }>
@@ -206,13 +208,13 @@
         dataIndex: 'operation',
         render: (text, record) =>
           (<div>
-            <span className="operation-btn" title={this.props.dict['header.edit']} onClick={() => this.handleEdit(record, 'customverify')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
+            <span className="operation-btn" title={this.props.dict['model.edit']} onClick={() => this.handleEdit(record, 'customverify')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
             <span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'customverify', 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
             <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'customverify', 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
             <span className="operation-btn" title={this.props.dict['header.form.status.change']} onClick={() => this.handleStatus(record, 'customverify')} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
             <Popconfirm
               title={this.props.dict['header.form.query.delete']}
-              okText={this.props.dict['header.confirm']}
+              okText={this.props.dict['model.confirm']}
               cancelText={this.props.dict['header.cancel']}
               onConfirm={() => this.handleDelete(record, 'customverify')
             }>
@@ -266,13 +268,13 @@
         dataIndex: 'operation',
         render: (text, record) =>
           (<div>
-            <span className="operation-btn" title={this.props.dict['header.edit']} onClick={() => this.handleEdit(record, 'scripts')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
+            <span className="operation-btn" title={this.props.dict['model.edit']} onClick={() => this.handleEdit(record, 'scripts')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
             <span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'scripts', 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
             <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'scripts', 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
             <span className="operation-btn" title={this.props.dict['header.form.status.change']} onClick={() => this.handleStatus(record, 'scripts')} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
             <Popconfirm
               title={this.props.dict['header.form.query.delete']}
-              okText={this.props.dict['header.confirm']}
+              okText={this.props.dict['model.confirm']}
               cancelText={this.props.dict['header.cancel']}
               onConfirm={() => this.handleDelete(record, 'scripts')
             }>
@@ -370,13 +372,13 @@
         dataIndex: 'operation',
         render: (text, record) =>
           (<div>
-            <span className="operation-btn" title={this.props.dict['header.edit']} onClick={() => this.handleEdit(record, 'ordercode')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
+            <span className="operation-btn" title={this.props.dict['model.edit']} onClick={() => this.handleEdit(record, 'ordercode')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
             <span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'ordercode', 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
             <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'ordercode', 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
             <span className="operation-btn" title={this.props.dict['header.form.status.change']} onClick={() => this.handleStatus(record, 'ordercode')} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
             <Popconfirm
               title={this.props.dict['header.form.query.delete']}
-              okText={this.props.dict['header.confirm']}
+              okText={this.props.dict['model.confirm']}
               cancelText={this.props.dict['header.cancel']}
               onConfirm={() => this.handleDelete(record, 'ordercode')
             }>
@@ -414,7 +416,8 @@
       verify: _verify
     })
 
-    if (this.props.card.btnType) { // 鎸夐挳-琛ㄥ崟鏍囩椤�
+    // 鎸夐挳-琛ㄥ崟鏍囩椤�
+    if (this.props.card.btnType) {
       let _fields = []
 
       config.groups.forEach(group => {
@@ -488,13 +491,118 @@
         Select ${_select.join(', ')}
       `
 
+      // 榛樿sql
+      let _insertsql = ''
+      let _updatesql = ''
+
+      if (this.props.card.sqlType === 'insert' || this.props.card.sqlType === 'insertOrUpdate') {
+        let keys = []
+        let values = []
+        _fields.forEach(item => {
+          if (!item.field) return
+
+          keys.push(item.field.toLowerCase())
+          values.push('@' + item.field)
+        })
+
+        if (config.setting.primaryKey && !keys.includes(config.setting.primaryKey.toLowerCase())) {
+          keys.push(config.setting.primaryKey.toLowerCase())
+          values.push('\'\'')
+        }
+        if (!keys.includes('createuserid')) {
+          keys.push('createuserid')
+          values.push('@userid@')
+        }
+        if (!keys.includes('createuser')) {
+          keys.push('createuser')
+          values.push('@username')
+        }
+        if (!keys.includes('createstaff')) {
+          keys.push('createstaff')
+          values.push('@fullname')
+        }
+        if (!keys.includes('bid')) {
+          keys.push('bid')
+          values.push('@BID@')
+        }
+  
+        keys = keys.join(',')
+        values = values.join(',')
+        _insertsql = `insert into ${this.props.card.sql} (${keys}) select ${values};`
+      }
+      
+      if (this.props.card.sqlType === 'update' || this.props.card.sqlType === 'insertOrUpdate') {
+        let _form = []
+        let _arr = []
+
+        _fields.forEach(item => {
+          if (!item.field) return
+
+          _arr.push(item.field.toLowerCase())
+          _form.push(item.field + '=@' + item.field)
+        })
+
+        if (!_arr.includes('modifydate')) {
+          _form.push('modifydate=getdate()')
+        }
+        if (!_arr.includes('modifyuserid')) {
+          _form.push('modifyuserid=@userid@')
+        }
+
+        if (_verify.voucher && _verify.voucher.enabled) {
+          if (!_arr.includes('bvoucher')) {
+            _form.push('BVoucher=@BVoucher')
+          }
+          if (!_arr.includes('fibvoucherdate')) {
+            _form.push('FIBVoucherDate=@FIBVoucherDate')
+          }
+          if (!_arr.includes('fiyear')) {
+            _form.push('FiYear=@FiYear')
+          }
+        }
+        
+        let primaryKeyName = config.setting.primaryKey
+        if (primaryKeyName && ['id', 'bid', 'loginuid', 'sessionuid', 'userid', 'appkey'].includes(primaryKeyName.toLowerCase())) {
+          primaryKeyName = primaryKeyName + '@'
+        }
+
+        _form = _form.join(',')
+        _updatesql = `update ${this.props.card.sql} set ${_form} where ${config.setting.primaryKey}=@${primaryKeyName};`
+      }
+
+      let _defaultsql = ''
+
+      if (this.props.card.sqlType === 'insert') {
+        _defaultsql = _insertsql
+      } else if (this.props.card.sqlType === 'update') {
+        _defaultsql = _updatesql
+      } else if (this.props.card.sqlType === 'insertOrUpdate') {
+        _defaultsql += `select @tbid=''
+          select @tbid='X' from ${this.props.card.sql} where ${config.setting.primaryKey}=@ID@
+          if @tbid=''
+            begin
+            ${_insertsql}
+            end
+          else
+            begin
+            ${_updatesql}
+            end
+        `
+      }
+
       this.setState({
         fields: _fields,
         initsql: _sql,
+        defaultsql: _defaultsql,
         usefulfields: _usefulfields
+      }, () => {
+        this.getsysScript()
       })
+
       return
     }
+
+    // 閫氱敤鎸夐挳
     if (this.props.card.OpenType === 'pop') {
       Api.getSystemConfig({
         func: 'sPC_Get_LongParam',
@@ -511,7 +619,17 @@
             }
           }
   
-          if (!_LongParam) return
+          if (!_LongParam) {
+            notification.warning({
+              top: 92,
+              message: '琛ㄥ崟鏈坊鍔犳垨瑙f瀽閿欒锛岃妫�鏌ヨ〃鍗曡缃紒',
+              duration: 5
+            })
+
+            this.getsysScript()
+
+            return
+          }
           
           let _fields = []
           if (_LongParam.groups.length > 0) {
@@ -527,6 +645,7 @@
           let _select = ['@UserName=\'\'', '@FullName=\'\'', '@ErrorCode=\'\'', '@retmsg=\'\'']
           let hasBid = false
           let fieldArr = _usefulfields.map(_f => _f.toLowerCase())
+          let _defaultfields = fromJS(_fields).toJS()
 
           _fields.forEach(_f => {
             if (_f.field) {
@@ -602,10 +721,89 @@
             Select ${_select.join(', ')}
           `
 
+          // 榛樿sql
+          let _defaultsql = ''
+
+          if (this.props.card.sqlType === 'insert') {
+            let keys = []
+            let values = []
+            _defaultfields.forEach(item => {
+              if (!item.field) return
+
+              keys.push(item.field.toLowerCase())
+              values.push('@' + item.field)
+            })
+
+            if (config.setting.primaryKey && !keys.includes(config.setting.primaryKey.toLowerCase())) {
+              keys.push(config.setting.primaryKey.toLowerCase())
+              values.push('\'\'')
+            }
+            if (!keys.includes('createuserid')) {
+              keys.push('createuserid')
+              values.push('@userid@')
+            }
+            if (!keys.includes('createuser')) {
+              keys.push('createuser')
+              values.push('@username')
+            }
+            if (!keys.includes('createstaff')) {
+              keys.push('createstaff')
+              values.push('@fullname')
+            }
+            if (!keys.includes('bid')) {
+              keys.push('bid')
+              values.push('@BID@')
+            }
+      
+            keys = keys.join(',')
+            values = values.join(',')
+            _defaultsql = `insert into ${this.props.card.sql} (${keys}) select ${values};`
+          } else if (this.props.card.sqlType === 'update') {
+            let _form = []
+            let _arr = []
+
+            _defaultfields.forEach(item => {
+              if (!item.field) return
+
+              _arr.push(item.field.toLowerCase())
+              _form.push(item.field + '=@' + item.field)
+            })
+
+            if (!_arr.includes('modifydate')) {
+              _form.push('modifydate=getdate()')
+            }
+            if (!_arr.includes('modifyuserid')) {
+              _form.push('modifyuserid=@userid@')
+            }
+
+            if (_verify.voucher && _verify.voucher.enabled) {
+              if (!_arr.includes('bvoucher')) {
+                _form.push('BVoucher=@BVoucher')
+              }
+              if (!_arr.includes('fibvoucherdate')) {
+                _form.push('FIBVoucherDate=@FIBVoucherDate')
+              }
+              if (!_arr.includes('fiyear')) {
+                _form.push('FiYear=@FiYear')
+              }
+            }
+            
+            let primaryKeyName = config.setting.primaryKey
+            if (primaryKeyName && ['id', 'bid', 'loginuid', 'sessionuid', 'userid', 'appkey'].includes(primaryKeyName.toLowerCase())) {
+              primaryKeyName = primaryKeyName + '@'
+            }
+
+            _form = _form.join(',')
+            _defaultsql = `update ${this.props.card.sql} set ${_form} where ${config.setting.primaryKey}=@${primaryKeyName};`
+          }
+          
           this.setState({
             fields: _fields,
             initsql: _sql,
+            defaultsql: _defaultsql,
             usefulfields: _usefulfields
+          }, () => {
+            this.getsysScript()
           })
         } else {
           notification.warning({
@@ -613,6 +811,7 @@
             message: res.message,
             duration: 5
           })
+          this.getsysScript()
         }
       })
     } else {
@@ -652,9 +851,36 @@
         Select ${_select.join(', ')}
       `
 
+      // 榛樿sql
+      let _defaultsql = ''
+      let primaryKeyName = config.setting.primaryKey
+
+      if (primaryKeyName && ['id', 'bid', 'loginuid', 'sessionuid', 'userid', 'appkey'].includes(primaryKeyName.toLowerCase())) {
+        primaryKeyName = primaryKeyName + '@'
+      }
+
+      if (this.props.card.sqlType === 'LogicDelete') {
+        _defaultsql = `update ${this.props.card.sql} set deleted=1,modifydate=getdate(),modifyuserid=@userid@ where ${config.setting.primaryKey}=@${primaryKeyName};`
+      } else if (this.props.card.sqlType === 'delete') {
+        let _msg = ''
+        if (columns && columns.length > 0 && this.props.card.Ot !== 'notRequired') {
+          let _index = 0
+          columns.forEach(col => {
+            if (col.field && col.Hide !== 'true' && _index < 4) {
+              _msg += col.label + '=\'\','
+              _index++
+            }
+          })
+        }
+        _defaultsql += `insert into snote (remark,createuserid,CreateUser,CreateStaff) select left('鍒犻櫎琛�:${this.props.card.sql} 鏁版嵁: ${_msg}${config.setting.primaryKey}='+@${primaryKeyName},200),@userid@,@username,@fullname delete ${this.props.card.sql} where ${config.setting.primaryKey}=@${primaryKeyName};`
+      }
+
       this.setState({
         initsql: _sql,
+        defaultsql: _defaultsql,
         usefulfields: _usefulfields
+      }, () => {
+        this.getsysScript()
       })
     }
   }
@@ -785,7 +1011,11 @@
         voucherDetail: result[1].data
       })
     })
-    
+  }
+
+  getsysScript = () => {
+    const { defaultsql } = this.state
+
     let _scriptSql = `Select distinct func+Remark as funcname,longparam, s.Sort from聽 s_custom_script s inner join (select OpenID from sapp where ID=@Appkey@) p on s.openid = case when s.appkey='' then s.openid else p.OpenID end order by s.Sort`
 
     _scriptSql = Utils.formatOptions(_scriptSql)
@@ -802,13 +1032,26 @@
     
     Api.getSystemConfig(_sParam).then(res => {
       if (res.status) {
-        this.setState({
-          systemScripts: res.data.map(item => {
-            return {
-              name: item.funcname,
-              value: Utils.formatOptions(item.longparam, true)
-            }
+        let _scripts = []
+
+        if (defaultsql) {
+          _scripts.push({
+            name: '榛樿sql',
+            value: defaultsql
           })
+        }
+
+        res.data.forEach(item => {
+          let _item = {
+            name: item.funcname,
+            value: Utils.formatOptions(item.longparam, true)
+          }
+
+          _scripts.push(_item)
+        })
+
+        this.setState({
+          systemScripts: _scripts
         })
       } else {
         notification.warning({
@@ -1216,7 +1459,7 @@
       if (_loading) {
         confirm({
           content: `瀛樺湪鏈繚瀛橀」锛岀‘瀹氭彁浜ゅ悧锛焋,
-          okText: this.props.dict['header.confirm'],
+          okText: this.props.dict['model.confirm'],
           cancelText: this.props.dict['header.cancel'],
           onOk() {
             resolve(verify)
@@ -1328,6 +1571,7 @@
           <TabPane tab="鑷畾涔夐獙璇�" key="3">
             <CustomForm
               dict={this.props.dict}
+              btn={this.props.card}
               initsql={this.state.initsql}
               usefulfields={this.state.usefulfields}
               customChange={this.customChange}
@@ -1379,6 +1623,7 @@
               usefulfields={this.state.usefulfields}
               initsql={this.state.initsql}
               dict={this.props.dict}
+              btn={this.props.card}
               customScripts={verify.scripts}
               systemScripts={this.state.systemScripts}
               scriptsChange={this.scriptsChange}
diff --git a/src/templates/zshare/verifycardexcelin/index.jsx b/src/templates/zshare/verifycardexcelin/index.jsx
index 5a81e00..9c38961 100644
--- a/src/templates/zshare/verifycardexcelin/index.jsx
+++ b/src/templates/zshare/verifycardexcelin/index.jsx
@@ -69,12 +69,12 @@
         render: (text, record) =>
           (
             <div>
-              <span className="operation-btn" title={this.props.dict['header.edit']} onClick={() => this.handleEdit(record, 'columns')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
+              <span className="operation-btn" title={this.props.dict['model.edit']} onClick={() => this.handleEdit(record, 'columns')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
               <span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'columns', 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
               <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'columns', 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
               <Popconfirm
                 title={this.props.dict['header.form.query.delete']}
-                okText={this.props.dict['header.confirm']}
+                okText={this.props.dict['model.confirm']}
                 cancelText={this.props.dict['header.cancel']}
                 onConfirm={() => this.handleDelete(record, 'columns')
               }>
@@ -126,13 +126,13 @@
         dataIndex: 'operation',
         render: (text, record) =>
           (<div>
-            <span className="operation-btn" title={this.props.dict['header.edit']} onClick={() => this.handleEdit(record, 'unique')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
+            <span className="operation-btn" title={this.props.dict['model.edit']} onClick={() => this.handleEdit(record, 'unique')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
             <span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'unique', 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
             <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'unique', 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
             <span className="operation-btn" title={this.props.dict['header.form.status.change']} onClick={() => this.handleStatus(record, 'unique')} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
             <Popconfirm
               title={this.props.dict['header.form.query.delete']}
-              okText={this.props.dict['header.confirm']}
+              okText={this.props.dict['model.confirm']}
               cancelText={this.props.dict['header.cancel']}
               onConfirm={() => this.handleDelete(record, 'unique')
             }>
@@ -178,13 +178,13 @@
         dataIndex: 'operation',
         render: (text, record) =>
           (<div>
-            <span className="operation-btn" title={this.props.dict['header.edit']} onClick={() => this.handleEdit(record, 'scripts')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
+            <span className="operation-btn" title={this.props.dict['model.edit']} onClick={() => this.handleEdit(record, 'scripts')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
             <span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'scripts', 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
             <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'scripts', 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
             <span className="operation-btn" title={this.props.dict['header.form.status.change']} onClick={() => this.handleStatus(record, 'scripts')} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
             <Popconfirm
               title={this.props.dict['header.form.query.delete']}
-              okText={this.props.dict['header.confirm']}
+              okText={this.props.dict['model.confirm']}
               cancelText={this.props.dict['header.cancel']}
               onConfirm={() => this.handleDelete(record, 'scripts')
             }>
@@ -552,7 +552,7 @@
           if (_loading) {
             confirm({
               content: `瀛樺湪鏈繚瀛橀」锛岀‘瀹氭彁浜ゅ悧锛焋,
-              okText: this.props.dict['header.confirm'],
+              okText: this.props.dict['model.confirm'],
               cancelText: this.props.dict['header.cancel'],
               onOk() {
                 resolve(_verify)
diff --git a/src/templates/zshare/verifycardexcelout/index.jsx b/src/templates/zshare/verifycardexcelout/index.jsx
index 8a660c3..cd33cc4 100644
--- a/src/templates/zshare/verifycardexcelout/index.jsx
+++ b/src/templates/zshare/verifycardexcelout/index.jsx
@@ -40,12 +40,12 @@
         render: (text, record) =>
           (
             <div>
-              <span className="operation-btn" title={this.props.dict['header.edit']} onClick={() => this.handleEdit(record, 'columns')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
+              <span className="operation-btn" title={this.props.dict['model.edit']} onClick={() => this.handleEdit(record, 'columns')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
               <span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'columns', 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
               <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'columns', 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
               <Popconfirm
                 title={this.props.dict['header.form.query.delete']}
-                okText={this.props.dict['header.confirm']}
+                okText={this.props.dict['model.confirm']}
                 cancelText={this.props.dict['header.cancel']}
                 onConfirm={() => this.handleDelete(record, 'columns')
               }>
diff --git a/src/templates/zshare/verifycardprint/editable/index.jsx b/src/templates/zshare/verifycardprint/editable/index.jsx
index fd98ed7..e328414 100644
--- a/src/templates/zshare/verifycardprint/editable/index.jsx
+++ b/src/templates/zshare/verifycardprint/editable/index.jsx
@@ -118,7 +118,7 @@
               <span className="operation-btn" title={props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
               <Popconfirm
                 title={props.dict['header.form.query.delete']}
-                okText={props.dict['header.confirm']}
+                okText={props.dict['model.confirm']}
                 cancelText={props.dict['header.cancel']}
                 onConfirm={() => this.handleDelete(record.key)
               }>
diff --git a/src/templates/zshare/viewdragelement/card.jsx b/src/templates/zshare/viewdragelement/card.jsx
new file mode 100644
index 0000000..b44ab02
--- /dev/null
+++ b/src/templates/zshare/viewdragelement/card.jsx
@@ -0,0 +1,48 @@
+import React from 'react'
+import { useDrag, useDrop } from 'react-dnd'
+import { Icon } from 'antd'
+import './index.scss'
+
+const Card = ({ id, card, moveCard, findCard, editCard, delCard }) => {
+  const originalIndex = findCard(id).index
+
+  const [{ isDragging }, drag] = useDrag({
+    item: { type: 'chart', id, originalIndex },
+    collect: monitor => ({
+      isDragging: monitor.isDragging(),
+    }),
+  })
+
+  const opacity = isDragging ? 0 : 1
+
+  const edit = () => {
+    editCard(id)
+  }
+  
+  const del = () => {
+    delCard(id)
+  }
+
+  const [, drop] = useDrop({
+    accept: 'chart',
+    canDrop: () => true,
+    hover({ id: draggedId }) {
+      if (!draggedId) return
+      if (draggedId !== id) {
+        const { index: overIndex } = findCard(id)
+        moveCard(draggedId, overIndex)
+      }
+    }
+  })
+
+  return (
+    <div className="chart-tab" style={{ opacity: opacity}}>
+      <div ref={node => drag(drop(node))}>
+        <Icon type={card.icon} />
+      </div>
+      <Icon className="edit" title="缂栬緫" type="edit" onClick={edit} />
+      {card.chartType !== 'table' ? <Icon className="edit close" title="鍒犻櫎" type="close" onClick={del} /> : null}
+    </div>
+  )
+}
+export default Card
diff --git a/src/templates/zshare/viewdragelement/index.jsx b/src/templates/zshare/viewdragelement/index.jsx
new file mode 100644
index 0000000..c09197a
--- /dev/null
+++ b/src/templates/zshare/viewdragelement/index.jsx
@@ -0,0 +1,85 @@
+import React, { useState } from 'react'
+import { useDrop } from 'react-dnd'
+import { is, fromJS } from 'immutable'
+import update from 'immutability-helper'
+import { Tabs } from 'antd'
+import Card from './card'
+import './index.scss'
+
+const { TabPane } = Tabs
+
+const Container = ({activeKey, list, handleList, handleMenu, deleteMenu, changetabview }) => {
+  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(_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 editCard = id => {
+    const { card } = findCard(id)
+    handleMenu(card)
+  }
+
+  const delCard = id => {
+    const { card } = findCard(id)
+    deleteMenu(card)
+  }
+
+  const changetab = id => {
+    if (activeKey === 'all') return
+    
+    changetabview(id)
+  }
+
+  const [, drop] = useDrop({
+    accept: 'chart'
+  })
+
+  return (
+    <div ref={drop} className="ant-row chart-edit-tab-box">
+      <Tabs activeKey={activeKey} onChange={changetab}>
+        {cards.map(card => (
+          <TabPane tab={
+            <div key={card.uuid}>
+              <Card
+                key={card.uuid}
+                id={card.uuid}
+                card={card}
+                moveCard={moveCard}
+                editCard={editCard}
+                delCard={delCard}
+                findCard={findCard}
+              />
+            </div>
+          } key={card.uuid}></TabPane>
+        ))}
+      </Tabs>
+      {/* {cards.map(card => (
+        <Card
+          id={card.uuid}
+          key={card.uuid}
+          card={card}
+          moveCard={moveCard}
+          editCard={editCard}
+          delCard={delCard}
+          findCard={findCard}
+        />
+      ))} */}
+    </div>
+  )
+}
+export default Container
diff --git a/src/templates/zshare/viewdragelement/index.scss b/src/templates/zshare/viewdragelement/index.scss
new file mode 100644
index 0000000..91c831e
--- /dev/null
+++ b/src/templates/zshare/viewdragelement/index.scss
@@ -0,0 +1,41 @@
+.chart-edit-tab-box {
+  padding-right: 100px;
+  display: inline-block;
+
+  .ant-tabs-bar {
+    border: 0;
+  }
+  .ant-tabs-tab {
+    margin: 0px;
+    padding: 0px;
+  }
+  .ant-tabs-ink-bar {
+    display: none!important;
+  }
+  .chart-tab {
+    position: relative;
+    width: 40px;
+    padding-top: 15px;
+    text-align: center;
+    display: inline-block;
+    
+    .edit {
+      position: absolute;
+      left: 0;
+      top: 0px;
+      color: #1890ff;
+      cursor: pointer;
+      display: none;
+    }
+    .edit.close {
+      left: 20px;
+      color: #ff4d4f;
+    }
+  }
+
+  .chart-tab:hover {
+    .edit {
+      display: inline-block;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/utils/modelutils.js b/src/utils/modelutils.js
new file mode 100644
index 0000000..eed79e0
--- /dev/null
+++ b/src/utils/modelutils.js
@@ -0,0 +1,1620 @@
+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 + '/') : ''
+
+export default class Utils {
+  /**
+   * @description 鐢熸垚32浣島uid string + 鏃堕棿
+   * @return {String}  uuid
+   */
+  static getuuid () {
+    let uuid = []
+    let timestamp = new Date().getTime()
+    let options = '0123456789abcdefghigklmnopqrstuv'
+    for (let i = 0; i < 19; i++) {
+      uuid.push(options.substr(Math.floor(Math.random() * 0x20), 1))
+    }
+    uuid = timestamp + uuid.join('')
+    return uuid
+  }
+
+  /**
+   * @description 鐢熸垚GUID
+   * @return {String}  guid
+   */
+  static getguid () {
+    // 浜х敓涓�涓柊鐨凣UID鍊�
+    let uuid = []
+    let d = new Date()
+    let options = '0123456789abcdefghigklmnopqrstuv'
+    for (let i = 0; i < 19; i++) {
+      uuid.push(options.substr(Math.floor(Math.random() * 0x20), 1))
+    }
+    uuid = moment().format('YYYYMMDDHHmmss') + d.getMilliseconds() + uuid.join('')
+    return uuid.toUpperCase()
+  }
+
+  /**
+   * @description md5鍔犲瘑
+   * @return {String}  str         鍔犲瘑涓�
+   * @return {String}  timestamp   鏃堕棿鎴�  
+   */
+  static encrypt (str, timestamp) {
+    let salt = 'mingke' // 鐩愬��
+    let _str = str + salt + timestamp
+    if (_str.length > 8000) {
+      _str = _str.slice(_str.length - 8000)
+    }
+    return md5(_str)
+  }
+
+  /**
+   * @description sql璇硶楠岃瘉
+   * @return {String}  sql    sql璇彞
+   * @return {String}  type   楠岃瘉绫诲瀷
+   */
+  static verifySql (sql, type) {
+    if (!sql) return ''
+    let chars = [
+      {key: 'create', reg: /(^|\s)create\s/ig},
+      {key: 'insert', reg: /(^|\s)insert\s/ig},
+      {key: 'delete', reg: /(^|\s)delete\s/ig},
+      {key: 'update', reg: /(^|\s)update\s/ig},
+      {key: 'set', reg: /(^|\s)set\s/ig},
+      {key: 'drop', reg: /(^|\s)drop\s/ig},
+      {key: 'alter', reg: /(^|\s)alter\s/ig},
+      {key: 'truncate', reg: /(^|\s)truncate\s/ig},
+      {key: 'if', reg: /(^|\s)if\s/ig},
+      {key: 'exec', reg: /exec/ig},
+      {key: 'OBJECT', reg: /object/ig},
+      {key: 'sys.', reg: /sys\./ig},
+      {key: 'kill', reg: /kill/ig}
+    ]
+
+    if (type === 'customscript') {
+      chars = chars.filter(char => !['insert', 'delete', 'update', 'set', 'if', 'exec'].includes(char.key))
+    }
+
+    let error = ''
+    chars.forEach(char => {
+      if (!error && char.reg.test(sql)) {
+        error = char.key
+      }
+    })
+
+    return error
+  }
+
+  /**
+   * @description sql鍔犲瘑
+   * @return {String}  value
+   */
+  static formatOptions (value, isUnFormat = false) {
+    if (!value) return ''
+
+    let salt = 'minKe' // 鐩愬��
+    // 鍏抽敭瀛楄浆鎹㈣鍒�
+    let format = [
+      { key: 'select', value: ' msltk ' },
+      { key: 'from', value: ' mfrmk ' },
+      { key: 'where', value: ' mwhrk ' },
+      { key: 'order by', value: ' modbk ' },
+      { key: 'asc', value: ' modack ' },
+      { key: 'desc', value: ' moddesk ' },
+      { key: 'top', value: ' mtpk ' },
+      { key: 'like', value: ' mlkk ' },
+      { key: 'not like', value: ' mnlkk ' },
+      { key: 'between', value: ' mbtnk ' },
+      { key: 'and', value: ' madk ' },
+      { key: 'insert', value: ' mistk ' },
+      { key: 'into', value: ' mitk ' },
+      { key: 'update', value: ' muptk ' },
+      { key: 'delete', value: ' mdelk ' },
+      { key: 'begin', value: ' mbgink ' },
+      { key: 'end', value: ' medk ' },
+      { key: 'if', value: ' mefk ' },
+      { key: 'while', value: ' mwilk ' },
+      { key: 'create', value: ' mcrtk ' },
+      { key: 'alter', value: ' matek ' },
+      { key: 'len', value: ' mlnk ' },
+      { key: 'left', value: ' mlftk ' },
+      { key: 'right', value: ' mritk ' },
+      { key: 'union', value: ' munok ' },
+      { key: 'varchar', value: ' mvcrk ' },
+      { key: 'getdate', value: ' mgtdtk ' },
+      { key: 'TRY', value: ' mtryonek ' },
+      { key: 'TRAN', value: ' mtrnk ' },
+      { key: 'goto', value: ' mgtk ' },
+      { key: 'set', value: ' mstk ' },
+      { key: 'ROLLBACK', value: ' mrlbkk ' }
+    ]
+
+    if (!isUnFormat) { // 鍔犲瘑
+      value = value.replace(/\n/ig, ' \n ')
+      // 鏇挎崲鍏抽敭瀛�
+      format.forEach(item => {
+        let reg = new RegExp('(^|\\s)' + item.key + '(\\s|$)', 'ig')
+        value = value.replace(reg, item.value)
+      })
+  
+      // 1銆佹浛鎹�%绗︼紙鏁版嵁搴撲腑瑙f瀽鍚巗ql鎶ラ敊锛�
+      value = value.replace(/%/ig, ' mpercent ')
+
+      // 1銆乪ncode缂栫爜锛堜腑鏂囧瓧绗﹁秴鍑篵ase64鍔犲瘑鑼冨洿锛夛紝2銆乥ase64鍔犲瘑
+      value = window.btoa(window.encodeURIComponent(value))
+  
+      // 鎻掑叆瀛楃
+      let index = Math.floor(value.length / 2)
+      value = value.slice(0, index) + salt + value.slice(index)
+  
+      // base64鍔犲瘑
+      value = window.btoa(value)
+    } else { // 瑙e瘑
+      try {
+        value = window.atob(value)
+        value = value.replace(salt, '')
+        value = window.decodeURIComponent(window.atob(value))
+
+        value = value.replace(/\smpercent\s/g, '%')
+
+        format.forEach(item => {
+          let reg = new RegExp(item.value, 'g')
+          value = value.replace(reg, ' ' + item.key + ' ')
+        })
+
+        value = value.replace(/\s\n\s/ig, '\n')
+        value = value.replace(/(^\s+|\s+$)/ig, '')
+      } catch {
+        console.warn('UnFormat Failure')
+        value = ''
+      }
+    }
+
+    return value
+  }
+
+  /**
+   * @description 鍒濆鍖栨悳绱㈡潯浠�
+   * @param {Array}   searches     鎼滅储鏉′欢
+   * @return {String}  searches    鏍煎紡鍖栧悗缁撴灉
+   */
+  static initMainSearch (searches) {
+    if (!searches || searches.length === 0) return []
+
+    let newsearches = []
+    searches.forEach(search => {
+      let item = {
+        key: search.field,
+        match: search.match,
+        type: search.type,
+        label: search.label,
+        value: search.initval,
+        required: search.required === 'true'
+      }
+      if (item.type === 'date') {
+        item.value = item.value ? moment().subtract(item.value, 'days').format('YYYY-MM-DD') : ''
+      } else if (item.type === 'datemonth') {
+        item.value = item.value ? moment().subtract(item.value, 'month').format('YYYY-MM') : ''
+      } else if (item.type === 'dateweek') {
+        item.value = item.value ? [moment().subtract(item.value * 7, 'days').startOf('week').format('YYYY-MM-DD'),
+          moment().subtract(item.value * 7, 'days').endOf('week').format('YYYY-MM-DD')] : ''
+      } else if (item.type === 'daterange') {
+        let _val = item.value
+        if (_val) {
+          try {
+            _val = JSON.parse(_val)
+          } catch {
+            _val = ''
+          }
+        }
+        item.value = _val ? [moment().subtract(_val[0], 'days').format('YYYY-MM-DD'),
+          moment().subtract(_val[1], 'days').format('YYYY-MM-DD')] : ''
+      } else if (item.type === 'multiselect') {
+        item.value = item.value ? item.value.split(',').filter(Boolean) : []
+      }
+      newsearches.push(item)
+    })
+    
+    return newsearches
+  }
+
+  /**
+   * @description 鍒濆鍖栨悳绱㈡潯浠�
+   * @param {Array}   searches     鎼滅储鏉′欢
+   * @return {String}  searches    鏍煎紡鍖栧悗缁撴灉
+   */
+  static formatCustomMainSearch (searches) {
+    if (!searches || searches.length === 0) return {}
+
+    let newsearches = {}
+    searches.forEach(item => {
+      if (item.type === 'date') {
+        let timetail = ''
+        let _val = item.value
+
+        if (item.match === '<' || item.match === '<=') {
+          timetail = ' 00:00:00.000'
+          if (_val) {
+            _val = moment(_val, 'YYYY-MM-DD').add(1, 'days').format('YYYY-MM-DD')
+          }
+        } else if (item.match === '>' || item.match === '>=') {
+          timetail = ' 00:00:00.000'
+        }
+
+        if (newsearches[item.key]) {
+          newsearches[item.key + '1'] = _val ? _val + timetail : null
+        } else {
+          newsearches[item.key] = _val ? _val + timetail : null
+        }
+      } else if (item.type === 'datemonth') {
+        // 鏈�-杩囨护鏉′欢锛屼粠鏈堝紑濮嬭嚦缁撴潫
+        let _startval = null
+        let _endval = null
+
+        if (item.value) {
+          _startval = moment(item.value, 'YYYY-MM').startOf('month').format('YYYY-MM-DD') + ' 00:00:00.000'
+          _endval = moment(item.value, 'YYYY-MM').endOf('month').add(1, 'days').format('YYYY-MM-DD') + ' 00:00:00.000'
+        }
+        
+        newsearches[item.key] = _startval
+        newsearches[item.key + '1'] = _endval
+      } else if (item.type === 'dateweek') {
+        let _endval = ''
+        if (item.value) {
+          _endval = moment(item.value[1], 'YYYY-MM-DD').add(1, 'days').format('YYYY-MM-DD')
+        }
+
+        newsearches[item.key] = item.value ? item.value[0] + ' 00:00:00.000' : null
+        newsearches[item.key + '1'] = item.value ? _endval + ' 00:00:00.000' : null
+      } else if (item.type === 'daterange') {
+        let _endval = ''
+        if (item.value) {
+          _endval = moment(item.value[1], 'YYYY-MM-DD').add(1, 'days').format('YYYY-MM-DD')
+        }
+
+        newsearches[item.key] = item.value ? item.value[0] + ' 00:00:00.000' : null
+        newsearches[item.key + '1'] = item.value ? _endval + ' 00:00:00.000' : null
+      } else if (item.type === 'text') {
+        item.key.split(',').forEach(field => { // 缁煎悎鎼滅储锛屾墍瀛楁鎷兼帴
+          newsearches[field] = item.value
+        })
+      } else if (item.type === 'multiselect') {
+        newsearches[item.key] = item.value.join(',')
+      } else {
+        newsearches[item.key] = item.value
+      }
+    })
+
+    Object.keys(newsearches).forEach(key => {
+      if (!newsearches[key]) {
+        delete newsearches[key]
+      }
+    })
+    
+    return newsearches
+  }
+
+  /**
+   * @description 鎷兼帴鎼滅储鏉′欢main
+   * @param {Array}   searches     鎼滅储鏉′欢
+   * @return {String}  searchText  鎷兼帴缁撴灉
+   */
+  static joinMainSearchkey (searches) {
+    if (!searches || searches.length === 0) return ''
+
+    let searchText = ''
+    searches.forEach(item => {
+      if (!item.value || (item.type === 'multiselect' && item.value.length === 0)) return
+      
+      searchText += (searchText !== '' ? ' AND ' : '')
+      if (item.type === 'text') {
+        let str = item.match === '=' ? '' : '%'
+        let fields = item.key.split(',').map(field => { // 缁煎悎鎼滅储锛屾墍瀛楁鎷兼帴
+          return field + ' ' + item.match + ' \'' + str + item.value + str + '\''
+        })
+
+        searchText += '(' + fields.join(' OR ') + ')'
+      } else if (item.type === 'select') {
+        let str = item.match === '=' ? '' : '%'
+
+        searchText += item.key + ' ' + item.match + ' \'' + str + item.value + str + '\''
+      } else if (item.type === 'multiselect') {
+
+        searchText += `'${item.value}' ` + item.match + ' \'%\'+' + item.key + '+\'%\''
+      } else if (item.type === 'date') {
+        let _val = item.value
+        let timetail = ' 00:00:00.000'
+        let _match = item.match
+
+        if (item.match === '<' || item.match === '<=') { // 鏃堕棿涓�<=鏃讹紝鍖归厤鍚庝竴澶╃殑0鐐癸紝鍖归厤鏂瑰紡涓�<
+          _match = '<'
+          _val = moment(_val, 'YYYY-MM-DD').add(1, 'days').format('YYYY-MM-DD')
+        } else if (item.match === '=') {
+          timetail = ''
+        }
+
+        searchText += '(' + item.key + ' ' + _match + ' \'' + _val + timetail + '\')'
+      } else if (item.type === 'datemonth') { // 鏈�-杩囨护鏉′欢锛屼粠鏈堝紑濮嬭嚦缁撴潫锛岀粨鏉熸椂闂翠负鏈堟湯鍔犱竴澶╃殑0鐐癸紝鏂瑰紡涓�<
+        let _startval = moment(item.value, 'YYYY-MM').startOf('month').format('YYYY-MM-DD') + ' 00:00:00.000'
+        let _endval = moment(item.value, 'YYYY-MM').endOf('month').add(1, 'days').format('YYYY-MM-DD') + ' 00:00:00.000'
+
+        searchText += '(' + item.key + ' >= \'' + _startval + '\' AND ' + item.key + ' < \'' + _endval + '\')'
+      } else if (item.type === 'dateweek') { // 鍛�-杩囨护鏉′欢
+        let _startval = item.value[0] + ' 00:00:00.000'
+        let _endval = moment(item.value[1], 'YYYY-MM-DD').add(1, 'days').format('YYYY-MM-DD') + ' 00:00:00.000'
+
+        searchText += '(' + item.key + ' >= \'' + _startval + '\' AND ' + item.key + ' < \'' + _endval + '\')'
+      } else if (item.type === 'daterange') {
+        let _startval = item.value[0] + ' 00:00:00.000'
+        let _endval = moment(item.value[1], 'YYYY-MM-DD').add(1, 'days').format('YYYY-MM-DD') + ' 00:00:00.000'
+
+        searchText += '(' + item.key + ' >= \'' + _startval + '\' AND ' + item.key + ' < \'' + _endval + '\')'
+      } else {
+        searchText += '(' + item.key + ' ' + item.match + ' \'' + item.value + '\')'
+      }
+    })
+
+    return searchText
+  }
+
+  /**
+   * @description 鎷兼帴鎼滅储鏉′欢datamanage
+   * @param {Array}   searches     鎼滅储鏉′欢
+   * @return {String}  searchText  鎷兼帴缁撴灉
+   */
+  static jointsearchkey (searches) {
+    if (!searches || searches.length === 0) return ''
+    let searchText = ''
+    searches.forEach(item => {
+      if (!item.value) return
+      searchText += (searchText !== '' ? ' AND ' : '')
+      if (item.type === 'text') {
+        let options = item.key.split(',').map(op => {
+          // equal鏃朵笉娣诲姞%
+          let str = item.op === 'equal' ? '' : '%'
+          return op + ' ' + item.op + ' \'' + str + item.value + str + '\''
+        })
+        searchText += '(' + options.join(' OR ') + ')'
+      } else if (item.type === 'date') {
+        searchText += '(' + item.key + ' ' + item.op + ' \'' + item.value + '\')'
+      } else {
+        searchText += '(' + item.key + ' ' + item.op + ' \'' + item.value + '\')'
+      }
+    })
+    return searchText
+  }
+
+  /**
+   * @description 鑾峰彇鍥剧墖鐪熷疄璺緞
+   * @return {String}    url 鍥剧墖璺緞
+   */
+  static getrealurl (url) {
+    if (!url) return ''
+
+    let baseurl = ''
+    if (process.env.NODE_ENV === 'production') {
+      baseurl = document.location.origin + '/' + service
+    } else {
+      baseurl = 'http://qingqiumarket.cn/' + service
+    }
+    // if (!/Content\/images\/upload\//.test(url)) {
+    //   baseurl = baseurl + 'Content/images/upload/'
+    // }
+    let realurl = url.match(/^http/) || url.match(/^\/\//) ? url : baseurl + url
+    return realurl
+  }
+
+  /**
+   * @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   鎼滅储鏉′欢淇℃伅
+   */
+  static getSelectQueryOptions (item) {
+    let arrfield = [item.valueField, item.valueText]
+
+    if (item.type === 'link') {
+      arrfield.push(item.linkField)
+    } else if (item.type === 'select' && item.linkSubField && item.linkSubField.length > 0) {
+      arrfield.push(...item.linkSubField)
+    }
+
+    arrfield = Array.from(new Set(arrfield))
+
+    let _datasource = item.dataSource
+    let sql = ''
+
+    if (/\s/.test(_datasource)) { // 鎷兼帴鍒悕
+      _datasource = '(' + _datasource + ') tb'
+    }
+
+    arrfield = arrfield.join(',')
+
+    if (item.orderBy) {
+      sql = 'select distinct ' + arrfield + ',' + item.orderBy + ' as orderfield from ' + _datasource + ' order by orderfield ' + item.orderType
+    } else {
+      sql = 'select distinct ' + arrfield + ' from ' + _datasource
+    }
+
+    return {
+      sql: sql,
+      field: arrfield
+    }
+  }
+
+  /**
+   * @description 鑾峰彇excel瀵煎叆鍙傛暟
+   * @return {String} btn   鎸夐挳
+   * @return {String} data  excel鏁版嵁
+   */
+  static getExcelInSql (item, data, dict) {
+    let btn = item.verify
+    let keys = ['delete', 'drop', 'insert', 'truncate', 'update']
+
+    let errors = []
+    let _topline = btn.range || 0
+    let upId = this.getuuid()
+
+    let _initCustomScript = '' // 鍒濆鍖栬剼鏈�
+    let _prevCustomScript = '' // 榛樿sql鍓嶆墽琛岃剼鏈�
+    let _backCustomScript = '' // 榛樿sql鍚庢墽琛岃剼鏈�
+
+    if (btn.scripts) {
+      btn.scripts.forEach(script => {
+        if (script.status === 'false') return
+
+        if (script.position === 'init') {
+          _initCustomScript += `
+          ${script.sql}
+          `
+        } else if (script.position === 'front') {
+          _prevCustomScript += `
+          ${script.sql}
+          `
+        } else {
+          _backCustomScript += `
+          ${script.sql}
+          `
+        }
+      })
+    }
+
+    let _Ltext = data.map((item, lindex) => {
+      let vals = btn.columns.map((col, cindex) => {
+        let val = item[col.Column] !== undefined ? item[col.Column] : ''
+        let _position = (_topline + lindex + 1) + dict['main.excel.line'] + ' ' + (cindex + 1) + dict['main.excel.column']  + ' '
+
+        if (/^Nvarchar/ig.test(col.type)) {
+          if (typeof(val) === 'number') {
+            val = val.toString()
+          }
+
+          val = val.replace(/(^\s*$)|\t*|\v*/ig, '')
+
+          if (!val && col.required === 'true') { // 蹇呭~鏍¢獙
+            let _error =  _position + dict['main.excel.content.emptyerror']
+            errors.push(_error)
+          } else if (val.length > col.limit) {    // 闀垮害鏍¢獙
+            let _error =  _position + dict['main.excel.content.maxlimit']
+            errors.push(_error)
+          } else {                               // 鍏抽敭瀛楁牎楠�
+            keys.forEach(key => {
+              let _patten = new RegExp('(^' + key + '\\s+)|(\\s+' + key + '\\s+)', 'ig')
+              if (_patten.test(val)) {
+                let _error = _position + dict['main.excel.includekey'] + key
+                errors.push(_error)
+              }
+            })
+          }
+        } else if (/^int/ig.test(col.type)) {
+          if (!val && val !== 0) {
+            let _error =  _position + dict['main.excel.content.emptyerror']
+            errors.push(_error)
+          } else {
+            let _val = val + ''
+
+            if (!/^(([^0][0-9]+|0)$)|^(([1-9]+)$)/.test(_val)) {               // 妫�楠屾槸鍚︿负鏁存暟
+              let _error = _position + dict['main.excel.content.interror']
+              errors.push(_error)
+            } else if ((col.min || col.min === 0) && val < col.min) {          // 鏈�灏忓�兼楠�
+              let _error = _position + dict['main.excel.content.limitmin']
+              errors.push(_error)
+            } else if ((col.max || col.max === 0) && val > col.max) {          // 鏈�澶у�兼楠�
+              let _error = _position + dict['main.excel.content.limitmax']
+              errors.push(_error)
+            }
+          }
+        } else if (/^Decimal/ig.test(col.type)) {
+          if (!val && val !== 0) {
+            let _error =  _position + dict['main.excel.content.emptyerror']
+            errors.push(_error)
+          } else {
+            let _val = val + ''
+            let _vals = _val.split('.')
+
+            if (!/^(([^0][0-9]+|0)\.([0-9]+)$)|^(([^0][0-9]+|0)$)|^(([1-9]+)\.([0-9]+)$)|^(([1-9]+)$)/.test(_val)) {                           // 妫�楠屾槸鍚︿负娴偣鏁�
+              let _error = _position + dict['main.excel.content.floaterror']
+              errors.push(_error)
+            } else if (_vals[0].length > 18) {                         // 妫�楠屾暣鏁颁綅
+              let _error = _position + dict['main.excel.content.floatIntover']
+              errors.push(_error)
+            } else if (_vals[1] && _vals[1].length > col.limit) {       // 鏈�灏忓�兼楠�
+              let _error = _position + dict['main.excel.content.floatPointover']
+              errors.push(_error)
+            } else if ((col.min || col.min === 0) && val < col.min) { // 鏈�灏忓�兼楠�
+              let _error = _position + dict['main.excel.content.limitmin']
+              errors.push(_error)
+            } else if ((col.max || col.max === 0) && val > col.max) { // 鏈�澶у�兼楠�
+              let _error = _position + dict['main.excel.content.limitmax']
+              errors.push(_error)
+            }
+          }
+        }
+        
+        return `'${val}' as ${col.Column}`
+      })
+
+      let _lineIndex = '0000' + (lindex + 1) + '0'
+      _lineIndex = _lineIndex.substring(_lineIndex.length - 6)
+
+      vals.push(`'${upId + _lineIndex}' as jskey`)
+
+      return `Select ${vals.join(',')}`
+    })
+
+    _Ltext = _Ltext.join(' Union all ')
+
+    let _sql = ''
+
+    if (item.intertype === 'inner' && !item.innerFunc) {
+      let _uniquesql = ''
+      if (btn.uniques && btn.uniques.length > 0) {
+        btn.uniques.forEach(unique => {
+          if (unique.status === 'false') return
+
+          let _fields = unique.field.split(',')
+          let _fields_ = _fields.map(_field => {
+            return `a.${_field}=b.${_field}`
+          })
+          _fields_ = _fields_.join(' and ')
+
+          if (unique.verifyType !== 'physical') {
+            _fields_ += ' and b.deleted=0'
+          }
+
+          _uniquesql += `
+          Set @tbid=''
+          Select top 1 @tbid=${_fields.join('+\' \'+')} from (select 1 as n,${unique.field} from @${item.sheet} ) a group by ${unique.field} having sum(n)>1
+
+          If @tbid!=''
+          Begin
+            select @ErrorCode='${unique.errorCode}',@retmsg=@tbid+' 閲嶅'
+            goto aaa
+          end
+
+          Set @tbid=''
+          Select top 1 @tbid=${_fields.join('+\' \'+')} from  @${item.sheet} a
+          Inner join ${item.sheet} b on ${_fields_}
+
+          If @tbid!=''
+          Begin
+            select @ErrorCode='${unique.errorCode}',@retmsg=@tbid+' 涓庡凡鏈夋暟鎹噸澶�'
+            goto aaa
+          end
+          `
+        })
+
+        if (_uniquesql) {
+          _uniquesql = 'Declare @tbid Nvarchar(512)' + _uniquesql
+        }
+      }
+
+      let declarefields = []
+      let fields = []
+
+      btn.columns.forEach(col => {
+        declarefields.push(`${col.Column} ${col.type}`)
+        fields.push(col.Column)
+      })
+
+      fields = fields.join(',')
+
+      let _insert = ''
+
+      if (_prevCustomScript) {
+        _insert += _prevCustomScript
+      }
+
+      if (btn.default !== 'false') {
+        _insert += `
+        Insert into ${item.sheet} (${fields},createuserid,createuser,createstaff,bid) 
+        Select ${fields},@userid@,@username,@fullname,@BID@ From @${item.sheet}
+        `
+      }
+
+      if (_backCustomScript) {
+        _insert += _backCustomScript
+      }
+
+      _sql = `declare @${item.sheet} table (${declarefields.join(',')},jskey nvarchar(50) )
+      Declare @UserName nvarchar(50),@FullName nvarchar(50),@ErrorCode nvarchar(50),@retmsg nvarchar(4000)
+
+      Select  @ErrorCode='', @retmsg=''
+      
+      select @UserName=UserName,@FullName=FullName from SUsers where UID=@UserID@
+      ${_initCustomScript}
+      Insert into  @${item.sheet} (${fields},jskey)
+      ${_Ltext}
+      ${_uniquesql}
+      ${_insert}
+      Delete @${item.sheet}
+
+      aaa: select @ErrorCode as ErrorCode,@retmsg as retmsg`
+
+    } else {
+      _sql = _Ltext
+    }
+
+    console.log(_sql)
+    return {
+      sql: _sql,
+      errors: errors.join('; ')
+    }
+  }
+
+  /**
+   * @description 浣跨敤绯荤粺鍑芥暟鏃讹紙sPC_TableData_InUpDe 锛夛紝鐢熸垚sql璇彞
+   * @return {String} type   鎵ц绫诲瀷
+   * @return {String} table  琛ㄥ悕
+   */
+  static getSysDefaultSql (btn, setting, formdata, param, data, logcolumns, tab) {
+    let primaryId = param.ID
+    let BID = param.BID
+    let verify = btn.verify || {}
+    let _formFieldValue = {}
+    let _actionType = null
+
+    if (verify.default !== 'false') { // 鍒ゆ柇鏄惁浣跨敤榛樿sql
+      _actionType = btn.sqlType
+    }
+
+    let _initCustomScript = '' // 鍒濆鍖栬剼鏈�
+    let _prevCustomScript = '' // 榛樿sql鍓嶆墽琛岃剼鏈�
+    let _backCustomScript = '' // 榛樿sql鍚庢墽琛岃剼鏈�
+
+    if (verify.scripts) {
+      verify.scripts.forEach(item => {
+        if (item.status === 'false') return
+
+        if (item.position === 'init') {
+          _initCustomScript += `
+          ${item.sql}
+          `
+        } else if (item.position === 'front') {
+          _prevCustomScript += `
+          ${item.sql}
+          `
+        } else {
+          _backCustomScript += `
+          ${item.sql}
+          `
+        }
+      })
+    }
+
+    // 闇�瑕佸0鏄庣殑鍙橀噺闆�
+    // let _vars = ['tbid', 'ErrorCode', 'retmsg', 'BillCode', 'BVoucher', 'FIBVoucherDate', 'FiYear', 'UserName', 'FullName', 'ID', 'BID', 'LoginUID', 'SessionUid', 'UserID', 'Appkey']
+    let _vars = ['tbid', 'errorcode', 'retmsg', 'billcode', 'bvoucher', 'fibvoucherdate', 'fiyear', 'username', 'fullname', 'modulardetailcode']
+
+    // 涓婚敭瀛楁
+    let primaryKey = setting.primaryKey || 'id'
+
+    // 绯荤粺鍙橀噺澹版槑涓庤缃垵濮嬪��
+    let _sql = `Declare @tbid nvarchar(50),@ErrorCode nvarchar(50),@retmsg nvarchar(4000),@BillCode nvarchar(50),@BVoucher nvarchar(50),@FIBVoucherDate nvarchar(50), @FiYear nvarchar(50), @UserName nvarchar(50),@FullName nvarchar(50),@ModularDetailCode nvarchar(50)
+      `
+
+    // let _initvars = ['ID', 'BID', 'LoginUID', 'SessionUid', 'UserID', 'Appkey'] // 宸茶祴鍊煎瓧娈甸泦
+    let _initvars = [] // 宸茶祴鍊煎瓧娈甸泦
+    let _initfields = []
+    let _declarefields = []
+
+    // 鑾峰彇瀛楁閿�煎
+    if (formdata) {
+      formdata.forEach(form => {
+        _formFieldValue[form.key] = form.value
+        let _key = form.key.toLowerCase()
+
+        if (!_initvars.includes(_key)) {
+          _initvars.push(_key)
+
+          if (form.type === 'number' && typeof(form.value) === 'number') {
+            _initfields.push(`@${_key}=${form.value}`)
+          } else {
+            _initfields.push(`@${_key}='${form.value}'`)
+          }
+        }
+        
+        if (!_vars.includes(_key)) {
+          _vars.push(_key)
+
+          if (form.fieldlen && form.fieldlen > 2048) {
+            form.fieldlen = 'max'
+          }
+
+          let _type = `nvarchar(${form.fieldlen})`
+
+          if (form.type.match(/date/ig)) {
+            _type = 'datetime'
+          } else if (form.type === 'number') {
+            _type = `decimal(18,${form.fieldlen})`
+          }
+
+          _declarefields.push(`@${_key} ${_type}`)
+        }
+      })
+    }
+
+    // 娣诲姞鏁版嵁涓瓧娈碉紝琛ㄥ崟鍊间紭鍏�(鎸夐挳涓嶉�夎鏃惰烦杩�)
+    if (data && btn.Ot !== 'notRequired') {
+      _formFieldValue = {...data, ..._formFieldValue}
+
+      if (logcolumns && logcolumns.length > 0) {
+        logcolumns.forEach(col => {
+          let _key = col.field.toLowerCase()
+
+          if (!_initvars.includes(_key)) {
+            _initvars.push(_key)
+
+            let _val = data.hasOwnProperty(col.field) ? data[col.field] : ''
+
+            if (col.type === 'number' && typeof(_val) === 'number') {
+              _initfields.push(`@${_key}=${_val}`)
+            } else {
+              _initfields.push(`@${_key}='${_val}'`)
+            }
+          }
+          
+          if (!_vars.includes(_key)) {
+            _vars.push(_key)
+
+            if (col.fieldlength && col.fieldlength > 2048) {
+              col.fieldlength = 'max'
+            }
+  
+            let _type = `nvarchar(${col.fieldlength || 50})`
+
+            if (col.type === 'number') {
+              let _length = col.decimal ? col.decimal : 0
+              _type = `decimal(18,${_length})`
+            } else if (col.type === 'picture' || col.type === 'textarea') {
+              _type = `nvarchar(${col.fieldlength || 512})`
+            }
+  
+            _declarefields.push(`@${_key} ${_type}`)
+          }
+        })
+      }
+    }
+
+    // 鍙橀噺澹版槑
+    _declarefields = _declarefields.join(',')
+    if (_declarefields) {
+      _sql += `,${_declarefields}
+        `
+    }
+
+    // 鍙橀噺璧嬪��
+    _initfields = _initfields.join(',')
+    if (_initfields) {
+      _sql += `select ${_initfields}
+        `
+    }
+
+    // 鍘婚櫎绂佺敤鐨勯獙璇�
+    if (verify.contrasts) {
+      verify.contrasts = verify.contrasts.filter(item => item.status !== 'false')
+    }
+    if (verify.uniques) {
+      verify.uniques = verify.uniques.filter(item => item.status !== 'false')
+    }
+    if (verify.customverifys) {
+      verify.customverifys = verify.customverifys.filter(item => item.status !== 'false')
+    }
+    if (verify.billcodes) {
+      verify.billcodes = verify.billcodes.filter(item => item.status !== 'false')
+    }
+
+    let userName = sessionStorage.getItem('User_Name') || ''
+    let fullName = sessionStorage.getItem('Full_Name') || ''
+
+    if (sessionStorage.getItem('isEditState') === 'true') {
+      userName = sessionStorage.getItem('CloudUserName') || ''
+      fullName = sessionStorage.getItem('CloudFullName') || ''
+    }
+
+    // 鍒濆鍖栧嚟璇佸強鐢ㄦ埛淇℃伅瀛楁
+    _sql += `select @BVoucher='',@FIBVoucherDate='',@FiYear='',@ErrorCode='',@retmsg='',@UserName='${userName}', @FullName='${fullName}'
+      `
+
+    if (_initCustomScript) {
+      _sql += _initCustomScript
+    }
+
+    // 鍚敤璐︽湡楠岃瘉
+    if (verify.accountdate === 'true') {
+      _sql += `exec s_FIBVoucherDateCheck @ErrorCode=@ErrorCode OUTPUT,@retmsg=@retmsg OUTPUT
+        if @ErrorCode!=''
+          GOTO aaa
+        `
+    }
+
+    // 澶辨晥楠岃瘉锛屾坊鍔犳暟鎹椂涓嶇敤
+    if (btn.sqlType !== 'insert' && verify.invalid === 'true' && setting.dataresource) {
+      let datasource = setting.dataresource
+      if (/\s/.test(datasource)) { // 鎷兼帴鍒悕
+        datasource = '(' + datasource + ') tb'
+      }
+
+      _sql += `select @tbid='', @ErrorCode='',@retmsg=''
+        select @tbid=${primaryKey} from ${datasource} where ${primaryKey} ='${primaryId}'
+        If @tbid=''
+        Begin
+          select @ErrorCode='E',@retmsg='鏁版嵁宸插け鏁�'
+          goto aaa
+        end
+        `
+    }
+
+    // 姣旇緝楠岃瘉
+    if (verify.contrasts && verify.contrasts.length > 0) {
+      verify.contrasts.forEach(item => {
+        _sql += `If ${item.frontfield} ${item.operator} ${item.backfield}
+          Begin
+            select @ErrorCode='${item.errorCode}',@retmsg='${item.errmsg}'
+              goto aaa
+          end
+          `
+      })
+    }
+
+    // 鍞竴鎬ч獙璇侊紝蹇呴』瀛樺湪琛ㄥ崟锛堣〃鍗曞瓨鍦ㄦ椂锛屼富閿潎涓哄崟鍊硷級,蹇呴』濉啓鏁版嵁婧�
+    if (formdata && verify.uniques && verify.uniques.length > 0) {
+      let hasBid = false // 妫�楠岃〃鍗曞強鍒楀瓧娈典腑鏄惁鏈塨id
+      let _keys_ = Object.keys(_formFieldValue).map(key => key.toLowerCase())
+      if (_keys_.includes('bid')) {
+        hasBid = true
+      }
+
+      verify.uniques.forEach(item => {
+        let _fieldValue = []                     // 琛ㄥ崟閿�煎field=value
+        let _value = []                          // 琛ㄥ崟鍊硷紝鐢ㄤ簬閿欒鎻愮ず
+        let _labels = item.fieldlabel.split(',') // 琛ㄥ崟鎻愮ず鏂囧瓧
+        let arr = [] // 楠岃瘉涓婚敭
+
+        item.field.split(',').forEach((_field, index) => {
+          let _fval = `'${_formFieldValue[_field]}'`
+          // if (['id', 'bid', 'loginuid', 'sessionuid', 'userid', 'appkey'].includes(_field.toLowerCase())) {
+          //   _fval = '@' + _field + '@'
+          // }
+          if (_field.toLowerCase() === 'bid' && !hasBid) { // 琛ㄥ崟涓病鏈塨id鍒欎娇鐢ㄧ郴缁焍id鍙橀噺
+            _fval = '@BID@'
+          }
+          arr.push(_field.toLowerCase())
+
+          _fieldValue.push(`${_field}=${_fval}`)
+          _value.push(`${_labels[index] || ''}锛�${_formFieldValue[_field] || ''}`)
+        })
+
+        let _verifyType = ''
+        if (item.verifyType === 'logic') {
+          _verifyType = ' and deleted=0'
+        }
+
+        if (!arr.includes(primaryKey.toLowerCase())) {
+          _fieldValue.push(`${primaryKey} !='${primaryId}'`)
+        }
+
+        _sql += `select @tbid='', @ErrorCode='',@retmsg=''
+          select @tbid='X' from ${btn.sql} where ${_fieldValue.join(' and ')}${_verifyType}
+          If @tbid!=''
+          Begin
+            select @ErrorCode='${item.errorCode}',@retmsg='${_value.join(', ')} 宸插瓨鍦�'
+            goto aaa
+          end
+          `
+      })
+    }
+    
+    // 鑷畾涔夐獙璇�
+    if (verify.customverifys && verify.customverifys.length > 0) {
+      verify.customverifys.forEach(item => {        
+        _sql += `select @tbid='', @ErrorCode='',@retmsg=''
+          select top 1 @tbid='X' from (${item.sql}) a
+          If @tbid ${item.result === 'true' ? '!=' : '='}''
+          Begin
+            select @ErrorCode='${item.errorCode}',@retmsg='${item.errmsg}'
+            goto aaa
+          end
+          `
+      })
+    }
+
+    // 鍗曞彿鐢熸垚锛屼娇鐢ㄤ笂绾d锛圔ID锛夋垨鍒楄〃鏁版嵁锛屽0鏄庡彉閲忥紙妫�楠岋級
+    let _billcodesSql  = ''
+    if (verify.billcodes && verify.billcodes.length > 0) {
+      verify.billcodes.forEach(item => {
+        let _ModularDetailCode = ''
+        let _lpline = ''
+        if (item.TypeCharOne === 'Lp') {
+          if (item.linkField === 'BID' && BID) { // 鏇挎崲bid
+            _lpline = `set @ModularDetailCode= 'Lp'+ right('${item.mark || btn.uuid}'+@BID@,48)`
+          } else {
+            _lpline = `set @ModularDetailCode= 'Lp'+ right('${item.mark || btn.uuid}'+@${item.linkField},48)`
+          }
+          _ModularDetailCode = '@ModularDetailCode'
+        } else if (item.TypeCharOne === 'BN') {
+          let _val = ''
+          if (item.linkField === 'BID' && BID) { // 鏇挎崲bid
+            _val = BID
+          } else if (data && data.hasOwnProperty(item.linkField)) {
+            _val = data[item.linkField]
+          }
+          _ModularDetailCode = `'${item.TypeCharOne + _val}'`
+        } else {
+          _ModularDetailCode = `'${item.ModularDetailCode}'`
+        }
+
+        let _declare = ''
+        let _key = item.field.toLowerCase()
+
+        if (!_vars.includes(_key)) {
+          _declare = `Declare @${_key} nvarchar(50)`
+          _vars.push(_key)
+        }
+
+        _billcodesSql += `${_declare}
+          select @BillCode='', @${_key}='', @ModularDetailCode=''
+          ${_lpline}
+          exec s_get_BillCode
+            @ModularDetailCode=${_ModularDetailCode},
+            @Type=${item.Type},
+            @TypeCharOne='${item.TypeCharOne}',
+            @TypeCharTwo ='${item.TypeCharTwo}',
+            @BillCode =@BillCode output,
+            @ErrorCode =@ErrorCode output, 
+            @retmsg=@retmsg output
+          if @ErrorCode!=''
+            goto aaa
+          set @${_key}=@BillCode
+          `
+      })
+
+      if (_actionType !== 'insertOrUpdate') {
+        _sql += _billcodesSql
+      }
+    }
+
+    let hasvoucher = false
+
+    // 鍑瘉-鏄剧ず鍒椾腑閫夊彇,蹇呴』閫夎
+    if (verify.voucher && verify.voucher.enabled && data) {
+      let _voucher = verify.voucher
+
+      hasvoucher = true
+
+      _sql += `exec s_BVoucher_Create
+          @Bill ='${data[_voucher.linkField]}',
+          @BVoucherType ='${_voucher.BVoucherType}',
+          @VoucherTypeOne ='${_voucher.VoucherTypeOne}',
+          @VoucherTypeTwo ='${_voucher.VoucherTypeTwo}',
+          @Type =${_voucher.Type},
+          @UserID=@UserID@,
+          @Username=@Username,
+          @FullName=@FullName,
+          @BVoucher =@BVoucher OUTPUT ,
+          @FIBVoucherDate =@FIBVoucherDate OUTPUT ,
+          @FiYear =@FiYear OUTPUT ,
+          @ErrorCode =@ErrorCode OUTPUT, 
+          @retmsg=@retmsg OUTPUT
+        if @ErrorCode!=''
+          GOTO aaa
+        `
+    }
+
+    let primaryKeyName = ['id', 'bid', 'loginuid', 'sessionuid', 'userid', 'appkey'].includes(primaryKey.toLowerCase()) ? primaryKey + '@' : primaryKey
+
+    let _insertsql = ''
+    if (_actionType === 'insert' || _actionType === 'insertOrUpdate') { // 娣诲姞璇彞
+      let keys = []
+      let values = []
+
+      formdata.forEach(item => {
+        keys.push(item.key.toLowerCase())
+        values.push('@' + item.key)
+      })
+
+      if (!keys.includes(primaryKey.toLowerCase())) {
+        keys.push(primaryKey.toLowerCase())
+        values.push('\'' + primaryId + '\'')
+      }
+      if (!keys.includes('createuserid')) {
+        keys.push('createuserid')
+        values.push('@userid@')
+      }
+      if (!keys.includes('createuser')) {
+        keys.push('createuser')
+        values.push('@username')
+      }
+      if (!keys.includes('createstaff')) {
+        keys.push('createstaff')
+        values.push('@fullname')
+      }
+      if (!keys.includes('bid')) {
+        if (tab && tab.foreignKey && !keys.includes(tab.foreignKey.toLowerCase())) {
+          keys.push(tab.foreignKey)
+        } else {
+          keys.push('bid')
+        }
+        values.push('@BID@')
+      } else if (tab && tab.foreignKey && !keys.includes(tab.foreignKey.toLowerCase())) {
+        keys.push(tab.foreignKey)
+        values.push('@BID@')
+      }
+
+      keys = keys.join(',')
+      values = values.join(',')
+      _insertsql = `insert into ${btn.sql} (${keys}) select ${values};`
+    }
+
+    let _updatesql = ''
+    if (_actionType === 'update' || _actionType === 'insertOrUpdate') { // 淇敼璇彞
+      let _form = []
+      let _arr = []
+
+      formdata.forEach(item => {
+        _arr.push(item.key.toLowerCase())
+        _form.push(item.key + '=@' + item.key)
+      })
+
+      if (!_arr.includes('modifydate')) {
+        _form.push('modifydate=getdate()')
+      }
+      if (!_arr.includes('modifyuserid')) {
+        _form.push('modifyuserid=@userid@')
+      }
+      if (hasvoucher) {
+        if (!_arr.includes('bvoucher')) {
+          _form.push('BVoucher=@BVoucher')
+        }
+        if (!_arr.includes('fibvoucherdate')) {
+          _form.push('FIBVoucherDate=@FIBVoucherDate')
+        }
+        if (!_arr.includes('fiyear')) {
+          _form.push('FiYear=@FiYear')
+        }
+      }
+      _form = _form.join(',')
+      _updatesql = `update ${btn.sql} set ${_form} where ${primaryKey}=@${primaryKeyName};`
+    }
+
+    if (_prevCustomScript) {
+      _sql += _prevCustomScript
+    }
+
+    // 娣诲姞銆佷慨鏀广�侀�昏緫鍒犻櫎銆佺墿鐞嗗垹闄�
+    if (_actionType === 'insert') {
+      _sql += _insertsql
+    } else if (_actionType === 'update') {
+      _sql += _updatesql
+    } else if (_actionType === 'LogicDelete') { // 閫昏緫鍒犻櫎
+      _sql += `update ${btn.sql} set deleted=1,modifydate=getdate(),modifyuserid=@userid@ where ${primaryKey}=@${primaryKeyName};`
+    
+    } else if (_actionType === 'delete') {      // 鐗╃悊鍒犻櫎
+      let _msg = ''
+      if (data && logcolumns && logcolumns.length > 0) {
+        let _index = 0
+        logcolumns.forEach(col => {
+          if (col.Hide !== 'true' && _index < 4) {
+            _msg += col.label + '=' + data[col.field] + ','
+            _index++
+          }
+        })
+      }
+      _sql += `insert into snote (remark,createuserid,CreateUser,CreateStaff) select left('鍒犻櫎琛�:${btn.sql} 鏁版嵁: ${_msg}${primaryKey}='+@${primaryKeyName},200),@userid@,@username,@fullname delete ${btn.sql} where ${primaryKey}=@${primaryKeyName};`
+    } else if (_actionType === 'insertOrUpdate') {
+      _sql += `select @tbid=''
+        select @tbid='X' from ${btn.sql} where ${primaryKey}=@ID@
+        if @tbid=''
+          begin
+          ${_billcodesSql}
+          ${_insertsql}
+          end
+        else
+          begin
+          ${_updatesql}
+          end
+      `
+    }
+
+    if (_backCustomScript) {
+      _sql += _backCustomScript
+    }
+
+    _sql += `
+      aaa: select @ErrorCode as ErrorCode,@retmsg as retmsg`
+    console.log(_sql)
+    return _sql
+  }
+
+  /**
+   * @description 鍒犻櫎瀛樺偍杩囩▼sql
+   * @return {String} name 瀛樺偍杩囩▼鍚嶇О
+   */
+  static dropfunc (name) {
+    return `IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID('${name}') AND type in (N'P', N'PC'))  mdrpk PROCEDURE ${name}`
+  }
+
+  /**
+   * @description 鍒涘缓椤甸潰瀛樺偍杩囩▼
+   * @return {String}
+   */
+  static getTableFunc (param, menu, config) {
+    let form = ''
+    let formParam = ''
+    let _vars = ['bid', 'pageindex', 'pagesize', 'ordercol', 'ordertype', 'exceltype', 'septmenuno', 'lang', 'debug', 'loginuid', 'sessionuid', 'userid', 'errorcode', 'retmsg']
+    let _columns = []
+    let primaryKey = config.setting.primaryKey || 'ID'
+
+    if (!_vars.includes(primaryKey.toLowerCase())) {
+      _vars.push(primaryKey.toLowerCase())
+      formParam = `mchr13k@${primaryKey} nvarchar(50)='',`
+    }
+
+    if (config.search && config.search.length > 0) {
+      let _fields = new Map()
+      config.search.forEach(item => {
+        if (item.field) {
+          let type = ''
+
+          if (item.type.match(/date/ig)) {
+            type = 'datetime=null'
+          } else {
+            type = 'nvarchar(50)=\'\''
+          }
+
+          item.field.split(',').forEach(cell => {
+            let _f = cell
+            if (_fields.has(cell)) {
+              _f = _f + '1'
+            }
+  
+            _fields.set(cell, true)
+
+            if (!_vars.includes(_f.toLowerCase())) {
+              _vars.push(_f.toLowerCase())
+              formParam = formParam + `mchr13k@${_f} ${type},`
+            }
+          })
+        }
+      })
+    }
+
+    if (config.columns && config.columns.length > 0) {
+      config.columns.forEach(item => {
+        if (item.field) {
+          _columns.push(`${item.field} as ${item.label}`)
+        }
+      })
+
+      form = `
+        declare @dc table (${_columns.join(',')})
+        
+        @tableid ='${menu.MenuID}'
+      `
+    }
+
+    let Ltext = `create proc ${param.innerFunc}
+    ( /*${menu.MenuName}*/
+    @appkey nvarchar(50)='',
+    @BID nvarchar(50)='',${formParam}
+    @PageIndex nvarchar(50)='',
+    @PageSize nvarchar(50)='',
+    @OrderCol nvarchar(50)='',
+    @OrderType nvarchar(50)='',
+    @exceltype nvarchar(50)='',
+    @sEPTMenuNo nvarchar(50)='${menu.MenuNo}',
+    @lang nvarchar(50)='',
+    @debug nvarchar(50)='',
+    @LoginUID nvarchar(50)='',
+    @SessionUid nvarchar(50)='',
+    @UserID nvarchar(50),
+    @ErrorCode nvarchar(50) out,
+    @retmsg nvarchar(4000) out
+    )
+    as
+    begin
+    declare  @BegindateTest datetime,@EnddateTest datetime
+    select  @BegindateTest=getdate()
+    set @ErrorCode=''
+    set @retmsg=''
+    BEGIN TRY
+      /*浜嬪姟鎿嶄綔*/
+      BEGIN TRAN
+        /*鍏蜂綋涓氬姟鎿嶄綔*/
+        
+        /* 
+        select top 10 * from sProcExcep order by id desc
+        
+        declare @UserName  nvarchar(50),@FullName nvarchar(50)
+        
+        select @UserName=UserName,@FullName=FullName from SUsers where UID=@UserID
+        ${form}
+        if 1=2
+        begin
+          set @ErrorCode='E'
+          set @retmsg='鍦ㄦ鍐欐姤閿�'
+          goto GOTO_RETURN
+        end
+        
+        insert into sNote (remark,createuserid,CreateUser,CreateStaff)
+        select '鍦ㄦ鍐欐棩蹇�',@UserID,@UserName,@FullName
+        */
+        
+      COMMIT TRAN
+      SET NOCOUNT ON
+      RETURN
+    END TRY
+    BEGIN CATCH
+      /*閿欒澶勭悊*/
+      ROLLBACK TRAN
+      DECLARE @ErrorMessage NVARCHAR(4000);
+      DECLARE @ErrorSeverity INT;
+      DECLARE @ErrorState INT;
+      
+      /*鎶婅嚜瀹氫箟鐨勫弸濂界殑閿欒淇℃伅鎻愮ず鍔犱笂*/
+      set @ErrorCode=cast(ERROR_NUMBER() as nvarchar(50))
+      SET @retmsg=ERROR_MESSAGE();
+      SELECT @ErrorMessage=ERROR_MESSAGE(),
+        @ErrorSeverity=ERROR_SEVERITY(),
+        @ErrorState=ERROR_STATE();
+        
+      RAISERROR(@ErrorMessage, /*-- Message text.*/
+        @ErrorSeverity, /*-- Severity.*/
+        @ErrorState  /*-- State.*/
+      );
+    END CATCH
+    
+    GOTO_RETURN:
+      ROLLBACK TRAN
+      
+    END`
+
+    Ltext = Ltext.replace(/\n\s{4}/ig, 'mchr13k')
+
+    return Ltext
+  }
+
+  /**
+   * @description 鍒涘缓瀛樺偍杩囩▼
+   * @return {String}
+   */
+  static getfunc (param, btn, menu, config) {
+    let form = ''
+    let formParam = ''
+    let _vars = ['bid', 'septmenuno', 'lang', 'debug', 'loginuid', 'sessionuid', 'userid', 'errorcode', 'retmsg']
+    let columns = config.columns
+    let primaryKey = config.setting.primaryKey || 'ID'
+
+    if (!_vars.includes(primaryKey.toLowerCase())) {
+      _vars.push(primaryKey.toLowerCase())
+      formParam = `mchr13k@${primaryKey} nvarchar(50)='',`
+    }
+
+    if (param.fields && param.fields.length > 0) {
+      let _fields = []
+      param.fields.forEach(item => {
+        if (item.field) {
+          let type = ''
+          if (item.type.match(/date/ig)) {
+            type = 'datetime=null'
+          } else if (item.type === 'number') {
+            type = `decimal(18,${item.decimal})=0`
+          } else {
+            type = 'nvarchar(50)=\'\''
+          }
+
+          if (!_vars.includes(item.field.toLowerCase())) {
+            _vars.push(item.field.toLowerCase())
+            formParam = formParam + `mchr13k@${item.field} ${type},`
+          }
+
+          _fields.push(item.field)
+        }
+      })
+
+      let field1 = _fields.join(',')
+      let field2 = _fields.join(',@')
+      let field3 = _fields.map(cell => {
+        return cell + '=@' + cell
+      })
+
+      field2 = field2 ? '@' + field2 : ''
+      field3 = field3.join(',')
+
+      form = `
+        insert into ${param.name} (${field1},createuserid) select ${field2},@UserID
+        
+        update ${param.name} set ${field3},modifydate=getdate(),modifyuserid=@UserID
+      `
+    } else if (btn.OpenType === 'prompt' || btn.OpenType === 'exec') {
+      form = `
+        update ${param.name} set ModifyDate=getdate(),ModifyUserID=@UserID where ${primaryKey}=@${primaryKey}
+      `
+    }
+
+    if (columns) {
+      let _col = []
+      let _field = []
+      columns.forEach(col => {
+        if (col.field) {
+          if (col.type === 'number') {
+            _col.push(col.field + ' decimal(18,2)')
+          } else {
+            _col.push(col.field + ' nvarchar(50)')
+          }
+          _field.push(col.field)
+        }
+      })
+      _col = _col.join(',')
+      _field = _field.join(',')
+
+      form = form + `
+        declare @dc table (${_col})
+        
+        insert into @dc (${_field})
+
+        @tableid ='${menu.MenuID}'
+      `
+    }
+
+    // 鎵撳嵃鑷畾涔夋ā鏉垮瓧娈垫彁绀�
+    let _printRemark = ''
+    if (btn.funcType === 'print') {
+      _printRemark = '/* 鑷畾涔夋暟鎹墦鍗版ā鏉挎椂锛岃浣跨敤TemplateID瀛楁 */'
+    }
+
+    let Ltext = `create proc ${param.funcName}
+    ( /*${menu.MenuName}  ${btn.label}*/
+    @appkey nvarchar(50)='',
+    @BID nvarchar(50)='',${formParam}
+    @sEPTMenuNo nvarchar(50)='${param.menuNo}',
+    @lang nvarchar(50)='',
+    @debug nvarchar(50)='',
+    @LoginUID nvarchar(50)='',
+    @SessionUid nvarchar(50)='',
+    @UserID nvarchar(50),
+    @ErrorCode nvarchar(50) out,
+    @retmsg nvarchar(4000) out
+    )
+    as
+    begin
+    declare  @BegindateTest datetime,@EnddateTest datetime
+    select  @BegindateTest=getdate()
+    set @ErrorCode=''
+    set @retmsg=''
+    BEGIN TRY
+      /*浜嬪姟鎿嶄綔*/
+      BEGIN TRAN
+        /*鍏蜂綋涓氬姟鎿嶄綔*/
+        ${_printRemark}
+        /* 
+        select top 10 * from sProcExcep order by id desc
+        
+        declare @UserName  nvarchar(50),@FullName nvarchar(50)
+        
+        select @UserName=UserName,@FullName=FullName from SUsers where UID=@UserID
+        ${form}
+        if 1=2
+        begin
+          set @ErrorCode='E'
+          set @retmsg='鍦ㄦ鍐欐姤閿�'
+          goto GOTO_RETURN
+        end
+        
+        insert into sNote (remark,createuserid,CreateUser,CreateStaff)
+        select '鍦ㄦ鍐欐棩蹇�',@UserID,@UserName,@FullName
+        */
+        
+      COMMIT TRAN
+      SET NOCOUNT ON
+      RETURN
+    END TRY
+    BEGIN CATCH
+      /*閿欒澶勭悊*/
+      ROLLBACK TRAN
+      DECLARE @ErrorMessage NVARCHAR(4000);
+      DECLARE @ErrorSeverity INT;
+      DECLARE @ErrorState INT;
+      
+      /*鎶婅嚜瀹氫箟鐨勫弸濂界殑閿欒淇℃伅鎻愮ず鍔犱笂*/
+      set @ErrorCode=cast(ERROR_NUMBER() as nvarchar(50))
+      SET @retmsg=ERROR_MESSAGE();
+      SELECT @ErrorMessage=ERROR_MESSAGE(),
+        @ErrorSeverity=ERROR_SEVERITY(),
+        @ErrorState=ERROR_STATE();
+        
+      RAISERROR(@ErrorMessage, /*-- Message text.*/
+        @ErrorSeverity, /*-- Severity.*/
+        @ErrorState  /*-- State.*/
+      );
+    END CATCH
+    
+    GOTO_RETURN:
+      ROLLBACK TRAN
+      
+    END`
+
+    Ltext = Ltext.replace(/\n\s{4}/ig, 'mchr13k')
+
+    return Ltext
+  }
+
+  /**
+   * @description 鍒涘缓瀵煎叆瀛樺偍杩囩▼
+   * @return {String}
+   */
+  static getexcelInfunc (param, btn, menu) {
+    let _verify = btn.verify
+
+    let _uniquesql = ''
+    if (_verify.uniques && _verify.uniques.length > 0) {
+      _verify.uniques.forEach(unique => {
+        if (unique.status === 'false') return
+
+        let _fields = unique.field.split(',')
+        let _fields_ = _fields.map(_field => {
+          return `a.${_field}=b.${_field}`
+        })
+        _fields_ = _fields_.join(' and ')
+
+        if (unique.verifyType !== 'physical') {
+          _fields_ += ' and b.deleted=0'
+        }
+
+        _uniquesql += `
+        Set @tbid=''
+        Select top 1 @tbid=${_fields.join('+\' \'+')} from (select 1 as n,${unique.field} from @${btn.sheet} ) a group by ${unique.field} having sum(n)>1
+
+        If @tbid!=''
+        Begin
+          select @ErrorCode='${unique.errorCode}',@retmsg=@tbid+' 閲嶅'
+          goto aaa
+        end
+
+        Set @tbid=''
+        Select top 1 @tbid=${_fields.join('+\' \'+')} from  @${btn.sheet} a
+        Inner join ${btn.sheet} b on ${_fields_}
+
+        If @tbid!=''
+        Begin
+          select @ErrorCode='${unique.errorCode}',@retmsg=@tbid+' 涓庡凡鏈夋暟鎹噸澶�'
+          goto aaa
+        end
+        `
+      })
+
+      if (_uniquesql) {
+        _uniquesql = `
+        Declare @tbid Nvarchar(512)
+        ${_uniquesql}`
+      }
+    }
+
+    let declarefields = []
+    let fields = []
+
+    _verify.columns.forEach(col => {
+      declarefields.push(`${col.Column} ${col.type}`)
+      fields.push(col.Column)
+    })
+
+    fields = fields.join(',')
+
+    let _sql = `declare @${btn.sheet} table (${declarefields.join(',')},jskey nvarchar(50))
+      Declare @UserName nvarchar(50),@FullName nvarchar(50)
+      
+      select @UserName=UserName,@FullName=FullName from SUsers where UID=@UserID
+      
+      Insert into @${btn.sheet} (${fields},jskey)
+
+      exec s_KeyWords_Replace
+      @LText=@LText, @BID=@BID,@LoginUID=@LoginUID,@SessionUid=@SessionUid,@UserID=@UserID,@ID=@ID
+      ${_uniquesql}
+      Insert into ${btn.sheet} (${fields},createuserid,createuser,createstaff,bid) 
+      Select ${fields},@userid,@username,@fullname,@BID From @${btn.sheet}
+
+      Delete @${btn.sheet}`
+
+    let Ltext = `create proc ${param.funcName}
+    ( /*${menu.MenuName}  ${btn.label}*/
+      @appkey nvarchar(50)='',
+      @ID nvarchar(50)='',
+      @BID nvarchar(50)='',
+      @Ltext nvarchar(max)='',
+      @sEPTMenuNo nvarchar(50)='${param.menuNo}', 
+      @secretkey nvarchar(50)='',
+      @timestamp nvarchar(50)='',
+      @lang nvarchar(50)='',
+      @LoginUID nvarchar(50)='',
+      @SessionUid nvarchar(50)='',
+      @UserID nvarchar(50), 
+      @ErrorCode nvarchar(50) out,
+      @retmsg nvarchar(4000) out
+    )
+    as
+    begin
+    declare @BegindateTest datetime,@EnddateTest datetime 
+    select @BegindateTest=getdate() 
+    set @ErrorCode=''
+    set @retmsg=''
+    BEGIN TRY
+      /*浜嬪姟鎿嶄綔*/
+      BEGIN TRAN
+        /*鍏蜂綋涓氬姟鎿嶄綔*/
+
+        /* 
+        ${_sql}
+        */
+        
+      COMMIT TRAN
+      SET NOCOUNT ON
+      RETURN
+    END TRY
+    BEGIN CATCH
+      /*閿欒澶勭悊*/
+      ROLLBACK TRAN
+      DECLARE @ErrorMessage NVARCHAR(4000);
+      DECLARE @ErrorSeverity INT;
+      DECLARE @ErrorState INT;
+      
+      /*鎶婅嚜瀹氫箟鐨勫弸濂界殑閿欒淇℃伅鎻愮ず鍔犱笂*/
+      set @ErrorCode=cast(ERROR_NUMBER() as nvarchar(50))
+      SET @retmsg=ERROR_MESSAGE();
+      SELECT @ErrorMessage=ERROR_MESSAGE(),
+        @ErrorSeverity=ERROR_SEVERITY(),
+        @ErrorState=ERROR_STATE();
+        
+      RAISERROR(@ErrorMessage, /*-- Message text.*/
+        @ErrorSeverity, /*-- Severity.*/
+        @ErrorState  /*-- State.*/
+      );
+    END CATCH
+    
+    GOTO_RETURN:
+      ROLLBACK TRAN
+      
+    END`
+
+    Ltext = Ltext.replace(/\n\s{4}/ig, 'mchr13k')
+
+    return Ltext
+  }
+}
\ No newline at end of file
diff --git a/src/utils/utils.js b/src/utils/utils.js
index 2a4bd06..eed79e0 100644
--- a/src/utils/utils.js
+++ b/src/utils/utils.js
@@ -74,7 +74,7 @@
     ]
 
     if (type === 'customscript') {
-      chars = chars.map(char => !['insert', 'delete', 'update', 'set', 'if', 'exec'].includes(char.key))
+      chars = chars.filter(char => !['insert', 'delete', 'update', 'set', 'if', 'exec'].includes(char.key))
     }
 
     let error = ''

--
Gitblit v1.8.0