king
2020-02-13 8904592cf12f091aece5d6fc564fd8478fc8988b
2020-02-13
25个文件已修改
10个文件已添加
4个文件已删除
3109 ■■■■■ 已修改文件
package-lock.json 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/en-US/main.js 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/zh-CN/main.js 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/commontable/index.jsx 234 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/formtab/actionList/index.jsx 77 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/formtab/actionList/index.scss 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/formtab/index.jsx 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/tableshare/actionList/index.jsx 109 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/tableshare/actionList/index.scss 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/tableshare/excelin/index.jsx 117 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/tableshare/excelin/index.scss 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/actionform/index.jsx 57 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/index.jsx 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/formtabconfig/editable/index.jsx 258 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/formtabconfig/editable/index.scss 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/formtabconfig/index.jsx 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/formtabconfig/modalform/index.jsx 416 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/formtabconfig/modalform/index.scss 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/formtabconfig/settingform/index.jsx 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/subtableconfig/index.jsx 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/tableshare/dragelement/card.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/tableshare/exceleditable/index.jsx 304 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/tableshare/exceleditable/index.scss 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/tableshare/verifycard/customform/index.jsx 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/tableshare/verifycard/customscript/index.jsx 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/tableshare/verifycard/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/tableshare/verifycardexcelin/columnform/index.jsx 168 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/tableshare/verifycardexcelin/columnform/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/tableshare/verifycardexcelin/customscript/index.jsx 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/tableshare/verifycardexcelin/customscript/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/tableshare/verifycardexcelin/index.jsx 510 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/tableshare/verifycardexcelin/index.scss 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/ushare/editable/index.jsx 78 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/ushare/editable/index.scss 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/ushare/modalform/index.jsx 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/option.js 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils.js 137 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package-lock.json
@@ -1941,6 +1941,15 @@
        }
      }
    },
    "adler-32": {
      "version": "1.2.0",
      "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.2.0.tgz",
      "integrity": "sha1-aj5r8KY5ALoVZSgIyxXGgT0aXyU=",
      "requires": {
        "exit-on-epipe": "1.0.1",
        "printj": "1.1.2"
      }
    },
    "agentframework": {
      "version": "0.9.22",
      "resolved": "https://registry.npmjs.org/agentframework/-/agentframework-0.9.22.tgz",
@@ -3340,6 +3349,17 @@
      "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
      "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
    },
    "cfb": {
      "version": "1.1.3",
      "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.1.3.tgz",
      "integrity": "sha512-joXBW0nMuwV9no7UTMiyVJnQL6XIU3ThXVjFUDHgl9MpILPOomyfaGqC290VELZ48bbQKZXnQ81UT5HouTxHsw==",
      "requires": {
        "adler-32": "1.2.0",
        "commander": "2.20.0",
        "crc-32": "1.2.0",
        "printj": "1.1.2"
      }
    },
    "chalk": {
      "version": "2.4.2",
      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
@@ -3527,6 +3547,22 @@
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
      "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
    },
    "codepage": {
      "version": "1.14.0",
      "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.14.0.tgz",
      "integrity": "sha1-jL4lSBMjVZ19MHVxsP/5HnodL5k=",
      "requires": {
        "commander": "2.14.1",
        "exit-on-epipe": "1.0.1"
      },
      "dependencies": {
        "commander": {
          "version": "2.14.1",
          "resolved": "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz",
          "integrity": "sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw=="
        }
      }
    },
    "collection-visit": {
      "version": "1.0.0",
@@ -3795,6 +3831,15 @@
        "is-directory": "0.3.1",
        "js-yaml": "3.13.1",
        "parse-json": "4.0.0"
      }
    },
    "crc-32": {
      "version": "1.2.0",
      "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.0.tgz",
      "integrity": "sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA==",
      "requires": {
        "exit-on-epipe": "1.0.1",
        "printj": "1.1.2"
      }
    },
    "create-ecdh": {
@@ -6483,6 +6528,11 @@
      "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
      "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw="
    },
    "exit-on-epipe": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz",
      "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw=="
    },
    "expand-brackets": {
      "version": "2.1.4",
      "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
@@ -7074,6 +7124,11 @@
      "version": "0.1.2",
      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
      "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
    },
    "frac": {
      "version": "1.1.2",
      "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz",
      "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA=="
    },
    "fragment-cache": {
      "version": "0.2.1",
@@ -12554,6 +12609,11 @@
        }
      }
    },
    "printj": {
      "version": "1.1.2",
      "resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz",
      "integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ=="
    },
    "private": {
      "version": "0.1.8",
      "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz",
@@ -14970,6 +15030,14 @@
      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
    },
    "ssf": {
      "version": "0.10.2",
      "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.10.2.tgz",
      "integrity": "sha512-rDhAPm9WyIsY8eZEKyE8Qsotb3j/wBdvMWBUsOhJdfhKGLfQidRjiBUV0y/MkyCLiXQ38FG6LWW/VYUtqlIDZQ==",
      "requires": {
        "frac": "1.1.2"
      }
    },
    "sshpk": {
      "version": "1.16.1",
      "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
@@ -16831,6 +16899,27 @@
        "async-limiter": "1.0.1"
      }
    },
    "xlsx": {
      "version": "0.15.5",
      "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.15.5.tgz",
      "integrity": "sha512-iWyTqe6UGTkp3XQOeeKPEBcZvmBfzIo3hDIVDfhGIEoTGVIq2JWEk6tIx0F+oKUje3pfZUx4V1W+P6892AB8kQ==",
      "requires": {
        "adler-32": "1.2.0",
        "cfb": "1.1.3",
        "codepage": "1.14.0",
        "commander": "2.17.1",
        "crc-32": "1.2.0",
        "exit-on-epipe": "1.0.1",
        "ssf": "0.10.2"
      },
      "dependencies": {
        "commander": {
          "version": "2.17.1",
          "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz",
          "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg=="
        }
      }
    },
    "xml-name-validator": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz",
package.json
@@ -76,7 +76,8 @@
    "webpack": "4.39.1",
    "webpack-dev-server": "3.2.1",
    "webpack-manifest-plugin": "2.0.4",
    "workbox-webpack-plugin": "4.3.1"
    "workbox-webpack-plugin": "4.3.1",
    "xlsx": "^0.15.5"
  },
  "scripts": {
    "dev": "set PORT=3001 && node scripts/start.js",
src/locales/en-US/main.js
@@ -18,6 +18,18 @@
  'main.action.primarykey.repetition': 'There are multiple primary keys!',
  'main.action.primarykey.repetitionbid': 'There are multiple BID!',
  'main.column.operation': '操作',
  'main.excel.line': '行',
  'main.excel.column': '列',
  'main.excel.includekey': '含有关键字',
  'main.excel.content.emptyerror': '内容不可为空',
  'main.excel.content.typeerror': '内容应为数值',
  'main.excel.content.interror': '内容应为整数',
  'main.excel.content.floaterror': '内容应为浮点数',
  'main.excel.content.floatIntover': '整数位超出范围',
  'main.excel.content.floatPointover': '小数位超出范围',
  'main.excel.content.maxlimit': '内容超长',
  'main.excel.content.limitmin': '小于最小值',
  'main.excel.content.limitmax': '大于最大值',
  'form.required.input': 'Please input ',
  'form.required.select': 'Please select '
}
src/locales/zh-CN/main.js
@@ -20,6 +20,18 @@
  'main.action.primarykey.repetitionbid': '存在多个BID!',
  'main.column.operation': '操作',
  'main.view.unenabled': '抱歉,你访问的页面未启用,请联系管理员。',
  'main.excel.line': '行',
  'main.excel.column': '列',
  'main.excel.includekey': '含有关键字',
  'main.excel.content.emptyerror': '内容不可为空',
  'main.excel.content.typeerror': '内容应为数值',
  'main.excel.content.interror': '内容应为整数',
  'main.excel.content.floaterror': '内容应为浮点数',
  'main.excel.content.floatIntover': '整数位超出范围',
  'main.excel.content.floatPointover': '小数位超出范围',
  'main.excel.content.maxlimit': '内容超长',
  'main.excel.content.limitmin': '小于最小值',
  'main.excel.content.limitmax': '大于最大值',
  'form.required.input': '请输入',
  'form.required.select': '请选择'
}
src/tabviews/commontable/index.jsx
@@ -20,6 +20,7 @@
import './index.scss'
const SubTabTable = asyncComponent(() => import('@/tabviews/subtabtable'))
const FormTab = asyncComponent(() => import('@/tabviews/formtab'))
const { TabPane } = Tabs
class NormalTable extends Component {
@@ -32,6 +33,7 @@
  state = {
    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    ContainerId: Utils.getuuid(), // 菜单外层html Id
    view: 'commontable',  // 当前页面默认为主表
    loadingview: true,    // 页面加载中
    viewlost: false,      // 页面丢失:1、未获取到配置-页面丢失;2、页面未启用
    lostmsg: '',          // 页面丢失时的提示信息
@@ -524,6 +526,7 @@
   */
  reloadview = () => {
    this.setState({
      view: 'commontable',
      loadingview: true,
      viewlost: false,
      lostmsg: '',
@@ -731,6 +734,16 @@
      tabs.splice(index + 1, 0, newtab)
      
      this.props.modifyTabview(tabs)
    } else if (btn.OpenType === 'blank') {
      this.setState({
        view: 'formtab',
        tabBtn: btn,
        tabParam: {
          btn: btn,
          data: data,
          arr_field: this.state.arr_field
        }
      })
    }
  }
@@ -760,121 +773,124 @@
  }
  render() {
    const { setting, searchlist, actions, columns, loadingview, viewlost, setsingle, pickup, isLinkMain, config } = this.state
    const { view, setting, searchlist, actions, columns, loadingview, viewlost, setsingle, pickup, isLinkMain, config } = this.state
    return (
      <div className={'commontable ' + (isLinkMain ? 'pick-control' : '')} id={this.state.ContainerId}>
        {loadingview && <Spin size="large" />}
        {searchlist && searchlist.length > 0 ?
          <MainSearch
            dict={this.state.dict}
            searchlist={searchlist}
            refreshdata={this.refreshbysearch}
          /> : null
        }
        {actions && setting.onload !== 'false' ?
          <MainAction
            ref="mainButton"
            BID=""
            type="main"
            setting={setting}
            actions={actions}
            dict={this.state.dict}
            MenuID={this.props.MenuID}
            logcolumns={this.state.logcolumns}
            ContainerId={this.state.ContainerId}
            refreshdata={this.refreshbyaction}
            triggerPopview={this.triggerPopview}
            gettableselected={this.gettableselected}
          /> : null
        }
        {columns && setting.onload !== 'false' ?
          <div className="main-table-box">
            {isLinkMain ?
              <div className="pickchange">
                {setting.tableType === 'checkbox' ? <Switch title="单选切换" checkedChildren="单" unCheckedChildren="多" defaultChecked={setsingle} onChange={this.checkChange} /> : null}
                {this.state.BIDs.mainTable && (setting.tableType === 'radio' || setsingle) ? <Switch title="收起" checkedChildren="开" unCheckedChildren="关" defaultChecked={pickup} onChange={this.pickupChange} /> : null}
              </div> : null
            }
            <MainTable
              ref="mainTable"
              pickup={pickup}
              setting={setting}
              columns={columns}
              setsingle={setsingle}
      <div>
        {view === 'commontable' ? <div className={'commontable ' + (isLinkMain ? 'pick-control' : '')} id={this.state.ContainerId}>
          {loadingview && <Spin size="large" />}
          {searchlist && searchlist.length > 0 ?
            <MainSearch
              dict={this.state.dict}
              data={this.state.data}
              total={this.state.total}
              searchlist={searchlist}
              refreshdata={this.refreshbysearch}
            /> : null
          }
          {actions && setting.onload !== 'false' ?
            <MainAction
              ref="mainButton"
              BID=""
              type="main"
              setting={setting}
              actions={actions}
              dict={this.state.dict}
              MenuID={this.props.MenuID}
              loading={this.state.loading}
              refreshdata={this.refreshbytable}
              buttonTrigger={this.buttonTrigger}
              handleTableId={this.handleTableId}
            />
          </div> : null
        }
        {setting && setting.onload !== 'false' &&
          config.tabgroups.map(group => {
            if (config[group].length === 0) return null
              logcolumns={this.state.logcolumns}
              ContainerId={this.state.ContainerId}
              refreshdata={this.refreshbyaction}
              triggerPopview={this.triggerPopview}
              gettableselected={this.gettableselected}
            /> : null
          }
          {columns && setting.onload !== 'false' ?
            <div className="main-table-box">
              {isLinkMain ?
                <div className="pickchange">
                  {setting.tableType === 'checkbox' ? <Switch title="单选切换" checkedChildren="单" unCheckedChildren="多" defaultChecked={setsingle} onChange={this.checkChange} /> : null}
                  {this.state.BIDs.mainTable && (setting.tableType === 'radio' || setsingle) ? <Switch title="收起" checkedChildren="开" unCheckedChildren="关" defaultChecked={pickup} onChange={this.pickupChange} /> : null}
                </div> : null
              }
              <MainTable
                ref="mainTable"
                pickup={pickup}
                setting={setting}
                columns={columns}
                setsingle={setsingle}
                dict={this.state.dict}
                data={this.state.data}
                total={this.state.total}
                MenuID={this.props.MenuID}
                loading={this.state.loading}
                refreshdata={this.refreshbytable}
                buttonTrigger={this.buttonTrigger}
                handleTableId={this.handleTableId}
              />
            </div> : null
          }
          {setting && setting.onload !== 'false' &&
            config.tabgroups.map(group => {
              if (config[group].length === 0) return null
            return (
              <Tabs defaultActiveKey="0" key={group}>
                {config[group].map((_tab, index) => {
                  return (
                    <TabPane tab={
                      <span>
                        {_tab.icon ? <Icon type={_tab.icon} /> : null}
                        {_tab.label}
                      </span>
                    } key={`${index}`}>
                      {_tab.type === 'SubTable' ?
                        <SubTable
                          Tab={_tab}
                          MenuID={_tab.linkTab}
                          SupMenuID={this.props.MenuID}
                          ContainerId={this.state.ContainerId}
                          BID={this.state.BIDs[_tab.supMenu] || ''}
                          BData={this.state.BIDs[_tab.supMenu + 'data'] || ''}
                          handleTableId={this.handleTableId}
                          handleMainTable={this.handleMainTable}
                        /> : null}
                    </TabPane>
                  )
                })}
              </Tabs>
            )
          })
        }
        <Modal
          className="popview-modal"
          title={this.state.popAction.label}
          width={'80vw'}
          maskClosable={false}
          visible={this.state.visible}
          onCancel={this.popclose}
          footer={[
            <Button key="cancel" onClick={this.popclose}>{this.state.dict['main.close']}</Button>
          ]}
          destroyOnClose
        >
          {<SubTabTable
            BID={''}
            SupMenuID={this.props.MenuID}
            MenuID={this.state.popAction.linkTab}
            BData={this.state.BIDs['mainTabledata'] || ''}
            ContainerId={this.state.ContainerId}
            ID={this.state.popData ? this.state.popData[setting.primaryKey] : ''}
            refreshSupView={this.reloadtable}
          />}
        </Modal>
        <BackTop>
          <div className="ant-back-top">
            <div className="ant-back-top-content">
              <div className="ant-back-top-icon"></div>
              return (
                <Tabs defaultActiveKey="0" key={group}>
                  {config[group].map((_tab, index) => {
                    return (
                      <TabPane tab={
                        <span>
                          {_tab.icon ? <Icon type={_tab.icon} /> : null}
                          {_tab.label}
                        </span>
                      } key={`${index}`}>
                        {_tab.type === 'SubTable' ?
                          <SubTable
                            Tab={_tab}
                            MenuID={_tab.linkTab}
                            SupMenuID={this.props.MenuID}
                            ContainerId={this.state.ContainerId}
                            BID={this.state.BIDs[_tab.supMenu] || ''}
                            BData={this.state.BIDs[_tab.supMenu + 'data'] || ''}
                            handleTableId={this.handleTableId}
                            handleMainTable={this.handleMainTable}
                          /> : null}
                      </TabPane>
                    )
                  })}
                </Tabs>
              )
            })
          }
          <Modal
            className="popview-modal"
            title={this.state.popAction.label}
            width={'80vw'}
            maskClosable={false}
            visible={this.state.visible}
            onCancel={this.popclose}
            footer={[
              <Button key="cancel" onClick={this.popclose}>{this.state.dict['main.close']}</Button>
            ]}
            destroyOnClose
          >
            {<SubTabTable
              BID={''}
              SupMenuID={this.props.MenuID}
              MenuID={this.state.popAction.linkTab}
              BData={this.state.BIDs['mainTabledata'] || ''}
              ContainerId={this.state.ContainerId}
              ID={this.state.popData ? this.state.popData[setting.primaryKey] : ''}
              refreshSupView={this.reloadtable}
            />}
          </Modal>
          <BackTop>
            <div className="ant-back-top">
              <div className="ant-back-top-content">
                <div className="ant-back-top-icon"></div>
              </div>
            </div>
          </div>
        </BackTop>
        {viewlost ? <NotFount msg={this.state.lostmsg} /> : null}
          </BackTop>
          {viewlost ? <NotFount msg={this.state.lostmsg} /> : null}
        </div> : null}
        {view === 'formtab' ? <FormTab MenuID={this.state.tabBtn.uuid} param={this.state.tabParam}/> : null}
      </div>
    )
  }
src/tabviews/formtab/actionList/index.jsx
@@ -1,7 +1,7 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import moment from 'moment'
import { Button, Modal, notification, Spin, message } from 'antd'
import { Button, Modal, notification, message } from 'antd'
import Utils from '@/utils/utils.js'
import Api from '@/api'
import './index.scss'
@@ -10,59 +10,28 @@
class MainAction extends Component {
  static propTpyes = {
    BData: PropTypes.any,          // 主表数据
    type: PropTypes.string,        // 判断当前为主表(main)、子表(sub)、子表标签(subtab)
    MenuID: PropTypes.string,      // 菜单ID
    actions: PropTypes.array,      // 按钮组
    logcolumns: PropTypes.array,   // 日志中显示列
    logcolumns: PropTypes.array,   // 显示列
    dict: PropTypes.object,        // 字典项
    data: PropTypes.any,           // 数据
    setting: PropTypes.any,        // 页面通用设置
    triggerPopview: PropTypes.func // 弹窗标签页触发
    refreshdata: PropTypes.func,   // 执行完成后数据刷新
  }
  state = {
    visible: false,
    formdata: null,
    tabledata: null,
    confirmLoading: false,
    loadingUuid: '',
    btnloading: false
    loadingUuid: ''
  }
  
  /**
   * @description 触发按钮操作
   */
  actionTrigger = (item, record) => {
    const { setting } = this.props
  actionTrigger = (item) => {
    const { data } = this.props
    let _this = this
    let data = this.props.gettableselected() || []
    if (item.Ot !== 'notRequired' && data.length === 0) {
      // 需要选择行时,校验数据
      notification.warning({
        top: 92,
        message: this.props.dict['main.action.confirm.selectline'],
        duration: 10
      })
      return
    } else if (item.Ot === 'requiredSgl' && data.length !== 1) {
      // 需要选择单行时,校验数据
      notification.warning({
        top: 92,
        message: this.props.dict['main.action.confirm.selectSingleLine'],
        duration: 10
      })
      return
    } else if (item.Ot !== 'notRequired' && !setting.primaryKey) {
      // 需要选择行时,校验是否设置主键
      notification.warning({
        top: 92,
        message: '未设置主键!',
        duration: 10
      })
      return
    }
    if (item.OpenType === 'prompt') {
      confirm({
@@ -78,17 +47,6 @@
      this.setState({loadingUuid: item.uuid})
      this.execSubmit(item, data, () => {
        this.setState({loadingUuid: ''})
      })
    } else if (item.OpenType === 'pop') {
      this.setState({
        tabledata: data,
        btnloading: true
      })
    } else {
      notification.warning({
        top: 92,
        message: '完善中。。。',
        duration: 10
      })
    }
  }
@@ -474,12 +432,6 @@
    } else if (res && res.ErrCode === '-1') { // 完成后不提示
    }
    if (btn.OpenType === 'pop' && btn.setting && btn.setting.finish !== 'unclose') {
      this.setState({
        visible: false
      })
    }
    this.props.refreshdata(btn, 'success')
  }
@@ -528,10 +480,10 @@
  
  render() {
    const { loadingUuid, btnloading } = this.state
    const { loadingUuid } = this.state
    return (
      <div className="button-list toolbar-button">
      <div className="button-list formtab-button">
        {this.props.actions.map((item, index) => {
          if (loadingUuid === item.uuid) {
            return (
@@ -554,17 +506,6 @@
            )
          }
        })}
        <Button
          className={'mk-btn'}
          // icon={item.icon}
          onClick={() => {this.actionTrigger()}}
        >确定</Button>
        <Button
          className={'mk-btn'}
          // icon={item.icon}
          onClick={() => {this.actionTrigger()}}
        >返回</Button>
        {btnloading && <Spin size="large" />}
      </div>
    )
  }
src/tabviews/formtab/actionList/index.scss
@@ -1,5 +1,5 @@
.button-list.toolbar-button {
  padding: 10px 20px 5px;
.button-list.formtab-button {
  padding: 20px 20px 10px;
  background: #ffffff;
  button {
    min-width: 65px;
@@ -13,30 +13,3 @@
    top: calc(50vh - 70px);
  }
}
// 设置模态框样式,规定最大最小高度,重置滚动条
.action-modal {
  .ant-modal {
    max-width: 95vw;
  }
  .ant-modal-body {
    max-height: calc(100vh - 235px);
    min-height: 150px;
    overflow-y: auto;
    padding-bottom: 35px;
  }
  .ant-modal-body::-webkit-scrollbar {
    width: 10px;
    height: 10px;
  }
  .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);
  }
}
src/tabviews/formtab/index.jsx
@@ -21,8 +21,8 @@
class NormalTable extends Component {
  static propTpyes = {
    MenuNo: PropTypes.string,    // 菜单参数
    MenuName: PropTypes.string,  // 菜单参数
    // MenuNo: PropTypes.string,    // 菜单参数
    // MenuName: PropTypes.string,  // 菜单参数
    MenuID: PropTypes.string,    // 菜单Id
    param: PropTypes.any         // 主表传递参数
  }
@@ -89,7 +89,7 @@
      }
      let _arrField = []     // 字段集
      console.log(this.props.param)
      if (this.props.param && this.props.param.arr_field) {
        _arrField = this.props.param.arr_field
      } else {
@@ -136,7 +136,7 @@
      let _isCustomData = false
      if (this.props.param && this.props.param.data) {
        _data = this.props.param.data
        _data = this.props.param.data[0] || null
      }
      if ((config.setting.interType === 'inner' && config.setting.innerFunc) || (config.setting.interType === 'outer' && config.setting.interface)) {
@@ -407,6 +407,7 @@
            setting={setting}
            actions={actions}
            dict={this.state.dict}
            data={this.state.data}
            MenuID={this.props.MenuID}
            logcolumns={[]}
            refreshdata={this.refreshbyaction}
src/tabviews/tableshare/actionList/index.jsx
@@ -3,6 +3,7 @@
import moment from 'moment'
import { Button, Affix, Modal, notification, Spin, message } from 'antd'
import MutilForm from '@/tabviews/tableshare/mutilform'
import ExcelIn from '../excelin'
import Utils from '@/utils/utils.js'
import Api from '@/api'
import './index.scss'
@@ -11,17 +12,19 @@
class MainAction extends Component {
  static propTpyes = {
    BID: PropTypes.string,         // 主表ID
    BData: PropTypes.any,          // 主表数据
    Tab: PropTypes.any,            // 如果当前元素为标签时,tab为标签信息
    type: PropTypes.string,        // 判断当前为主表(main)、子表(sub)、子表标签(subtab)
    MenuID: PropTypes.string,      // 菜单ID
    actions: PropTypes.array,      // 按钮组
    logcolumns: PropTypes.array,   // 日志中显示列
    dict: PropTypes.object,        // 字典项
    setting: PropTypes.any,        // 页面通用设置
    ContainerId: PropTypes.any,    // tab页面ID,用于弹窗控制
    triggerPopview: PropTypes.func // 弹窗标签页触发
    BID: PropTypes.string,            // 主表ID
    BData: PropTypes.any,             // 主表数据
    Tab: PropTypes.any,               // 如果当前元素为标签时,tab为标签信息
    type: PropTypes.string,           // 判断当前为主表(main)、子表(sub)、子表标签(subtab)
    MenuID: PropTypes.string,         // 菜单ID
    actions: PropTypes.array,         // 按钮组
    logcolumns: PropTypes.array,      // 日志中显示列
    dict: PropTypes.object,           // 字典项
    setting: PropTypes.any,           // 页面通用设置
    ContainerId: PropTypes.any,       // tab页面ID,用于弹窗控制
    refreshdata: PropTypes.func,      // 执行完成后数据刷新
    triggerPopview: PropTypes.func,   // 弹窗标签页触发
    gettableselected: PropTypes.func  // 获取表格中数据
  }
  state = {
@@ -113,6 +116,16 @@
    } else if (item.OpenType === 'excelOut') {
      this.setState({loadingUuid: item.uuid})
      this.refreshdata(item, 'excelOut')
    } else if (item.OpenType === 'excelIn') {
      if (item.verify && item.verify.sheet && item.verify.columns && item.verify.columns.length > 0) {
        this.refs.excelIn.exceltrigger(item)
      } else {
        notification.warning({
          top: 92,
          message: 'excel导入验证信息未设置!',
          duration: 10
        })
      }
    } else if (item.OpenType === 'popview' && this.props.type !== 'subtab') {
      this.props.triggerPopview(item, data)
    } else if (item.OpenType === 'popview' && this.props.type === 'subtab') {
@@ -525,7 +538,7 @@
   * 5、通知主列表刷新
   */
  execSuccess = (btn, res) => {
    if (btn.OpenType === 'excelOut') { // 导出excel
    if (btn.OpenType === 'excelOut' || btn.OpenType === 'excelIn') { // 导出excel
      this.setState({
        loadingUuid: ''
      })
@@ -584,7 +597,7 @@
      message.error(res.message || res.ErrMesg)
    }
    
    if (btn.OpenType === 'excelOut') {
    if (btn.OpenType === 'excelOut' || btn.OpenType === 'excelIn') {
      this.setState({
        loadingUuid: ''
      })
@@ -778,6 +791,74 @@
    })
  }
  getexceldata = (data, btn, errors) => {
    if (errors && errors.length > 0) {
      notification.warning({
        top: 92,
        message: errors.join(',') + '表头设置错误!',
        duration: 10
      })
      return
    }
    if (!data || data.length === 0) {
      notification.warning({
        top: 92,
        message: '未获取到excel数据!',
        duration: 10
      })
      return
    }
    let result = Utils.getExcelInSql(btn, data, this.props.dict)
    if (result.errors) {
      notification.warning({
        top: 92,
        message: result.errors,
        duration: 10
      })
      return
    }
    if (!btn.innerFunc) {
      let param = { // 系统存储过程
        func: 'sPC_TableData_InUpDe',
        BID: this.props.BID
      }
      param.LText = Utils.formatOptions(result.sql)
      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
      param.secretkey = Utils.encrypt(param.LText, param.timestamp)
      this.setState({loadingUuid: btn.uuid})
      Api.genericInterface(param).then((res) => {
        if (res.status) {
          this.execSuccess(btn, res)
        } else {
          this.execError(res, btn)
        }
      })
    } else {
      let param = { // 自定义存储过程
        func: btn.innerFunc,
        BID: this.props.BID
      }
      param.LText = Utils.formatOptions(result.sql)
      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
      param.secretkey = Utils.encrypt(param.LText, param.timestamp)
      this.setState({loadingUuid: btn.uuid})
      Api.genericInterface(param).then((res) => {
        if (res.status) {
          this.execSuccess(btn, res)
        } else {
          this.execError(res, btn)
        }
      })
    }
  }
  /**
   * @description 模态框(表单),确认
   */
@@ -948,6 +1029,7 @@
            })}
            {this.getModels()}
            {btnloading && <Spin size="large" />}
            <ExcelIn MenuID={this.props.MenuID} returndata={this.getexceldata} ref="excelIn" />
          </div>
        </Affix>
      )
@@ -978,6 +1060,7 @@
          })}
          {this.getModels()}
          {btnloading && <Spin size="large" />}
          <ExcelIn MenuID={this.props.MenuID} returndata={this.getexceldata} ref="excelIn" />
        </div>
      )
    }
src/tabviews/tableshare/actionList/index.scss
@@ -1,10 +1,12 @@
.button-list.toolbar-button {
  position: relative;
  padding: 10px 20px 5px;
  background: #ffffff;
  button {
    min-width: 65px;
    margin-right: 15px;
    margin-bottom: 10px;
    overflow: hidden;
  }
  .ant-spin {
    position: fixed;
src/tabviews/tableshare/excelin/index.jsx
New file
@@ -0,0 +1,117 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { notification } from 'antd'
import * as XLSX from 'xlsx'
import Utils from '@/utils/utils.js'
import './index.scss'
class ExcelIn extends Component {
  static propTpyes = {
    MenuID: PropTypes.string,     // 菜单ID
    returndata: PropTypes.func    // 菜单ID
  }
  state = {
    excelbtn: null,
    excelId: Utils.getuuid()
  }
  exceltrigger = (item) => {
    const { excelId } = this.state
    this.setState({
      excelbtn: item
    })
    let _excelInput = document.getElementById(excelId + this.props.MenuID)
    if (_excelInput) {
      _excelInput.click()
    }
  }
  onImportExcel = file => {
    const { excelbtn } = this.state
    let columns = excelbtn.verify.columns.map(option => option.Column)
    let range = excelbtn.verify.range || 0
    // excel数据处理
    const { files } = file.target
    const fileReader = new FileReader()
    fileReader.onload = event => {
      try {
        const { result } = event.target
        // 以二进制流方式读取得到整份excel表格对象
        const workbook = XLSX.read(result, { type: 'binary' })
        let errors = []
        if (range === 1) {
          workbook.SheetNames.forEach(sheetname => {
            if (workbook.Sheets.hasOwnProperty(sheetname)) {
              let header = XLSX.utils.sheet_to_json(workbook.Sheets[sheetname], {header: columns})[0]
              if (!header) {
                errors.push(sheetname)
              } else {
                let iserror = false
                excelbtn.verify.columns.forEach(op => {
                  if (header[op.Column] !== op.Text) {
                    iserror = true
                  }
                })
                if (iserror) {
                  errors.push(sheetname)
                }
              }
            }
          })
        }
        let data = []
        workbook.SheetNames.forEach(sheetname => {
          if (workbook.Sheets.hasOwnProperty(sheetname)) {
            data = data.concat(XLSX.utils.sheet_to_json(workbook.Sheets[sheetname], {header: columns, range: (range)}))
          }
        })
        // 最终获取到并且格式化后的 json 数据
        this.props.returndata(data, excelbtn, errors)
        this.setState({
          excelId: ''
        }, () => {
          this.setState({
            excelId: Utils.getuuid()
          })
        })
      } catch (e) {
        this.setState({
          excelId: ''
        }, () => {
          this.setState({
            excelId: Utils.getuuid()
          })
        })
        notification.warning({
          top: 92,
          message: '文件解析错误,请检查文件格式!',
          duration: 10
        })
      }
    }
    // 以二进制方式打开文件
    fileReader.readAsBinaryString(files[0])
  }
  render() {
    return (
      <span>
        {this.state.excelId ? <input className="excel-in-input" id={this.state.excelId + this.props.MenuID} type='file' accept='.xlsx, .xls' onChange={this.onImportExcel} /> : null}
      </span>
    )
  }
}
export default ExcelIn
src/tabviews/tableshare/excelin/index.scss
New file
@@ -0,0 +1,5 @@
.excel-in-input {
  position: absolute;
  opacity: 0;
  z-index: -1;
}
src/templates/comtableconfig/actionform/index.jsx
@@ -100,12 +100,14 @@
      _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 === 'excelIn' || _opentype === 'excelOut') {    // 导入导出
    } else if (_opentype === 'excelOut') {    // 导入导出
      if (_intertype === 'outer') {
        _options = ['label', 'OpenType', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc', 'icon', 'class', 'execSuccess', 'execError', 'method']
      } else {
        _options = ['label', 'OpenType', 'intertype', 'innerFunc', 'icon', 'class', 'execSuccess', 'execError']
      }
    } else if (_opentype === 'excelIn') {    // 导入导出
      _options = ['label', 'OpenType', 'intertype', 'innerFunc', 'icon', 'class', 'execSuccess', 'execError']
    } else {
      if (_intertype === 'outer') {
        _options = ['label', 'position', 'OpenType', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError', 'method']
@@ -147,6 +149,9 @@
          if (!initTab) {
            item.initVal = ''
          }
        } else if (item.key === 'intertype' && _opentype === 'excelIn') {
          item.initVal = 'inner'
          item.readonly = true
        }
        item.hidden = !_options.includes(item.key)
        return item
@@ -184,12 +189,14 @@
        _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 === 'excelIn' || value === 'excelOut') {
      } else if (value === 'excelOut') {
        if (this.state.interType === 'outer') {
          _options = ['label', 'OpenType', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc', 'icon', 'class', 'execSuccess', 'execError', 'method']
        } else {
          _options = ['label', 'OpenType', 'intertype', 'innerFunc', 'icon', 'class', 'execSuccess', 'execError']
        }
      } else if (value === 'excelIn') {
        _options = ['label', 'OpenType', 'intertype', 'innerFunc', 'icon', 'class', 'execSuccess', 'execError']
      } else {
        if (this.state.interType === 'inner') {
          _options = ['label', 'position', 'OpenType', 'intertype', 'innerFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError', 'sql', 'sqlType']
@@ -205,8 +212,12 @@
        if (item.hidden) return item
        if (item.key === 'intertype') {
        if (item.key === 'intertype' && value === 'excelIn') {
          _fieldval.intertype = 'inner'
          item.readonly = true
        } else if (item.key === 'intertype' && value !== 'excelIn') {
          _fieldval.intertype = this.state.interType
          item.readonly = false
        } else if (item.key === 'Ot') {
          if (value === 'innerpage' || this.state.position === 'grid') {
            item.options = this.state.reqOptionSgl
@@ -282,13 +293,28 @@
  }
  onChange = (e, key) => {
    const { openType } = this.state
    let value = e.target.value
    if (key === 'intertype') {
      let _options = null
      if (value === 'inner') {
        _options = ['label', 'position', 'OpenType', 'intertype', 'innerFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError', 'sql', 'sqlType']
      if (openType === 'excelOut') {
        if (value === 'outer') {
          _options = ['label', 'OpenType', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc', 'icon', 'class', 'execSuccess', 'execError', 'method']
        } else {
          _options = ['label', 'OpenType', 'intertype', 'innerFunc', 'icon', 'class', 'execSuccess', 'execError']
        }
      } else if (openType === 'excelIn') {
        if (value === 'outer') {
          _options = ['label', 'OpenType', 'intertype', 'innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc', 'icon', 'class', 'execSuccess', 'execError', 'method']
        } else {
          _options = ['label', 'OpenType', 'intertype', 'innerFunc', 'icon', 'class', 'execSuccess', 'execError']
        }
      } else {
        _options = ['label', 'position', 'OpenType', 'intertype', 'innerFunc', 'Ot', 'icon', 'class', 'execSuccess', 'execError', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc', 'method']
        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', 'method']
        }
      }
      this.setState({
@@ -379,7 +405,7 @@
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'number') { // 文本搜索
      } else if (item.type === 'number') {
        fields.push(
          <Col span={12} key={index}>
            <Form.Item label={item.tooltip ?
@@ -389,8 +415,14 @@
              </Tooltip> : item.label
            }>
              {getFieldDecorator(item.key, {
                initialValue: item.initVal
              })(<InputNumber min={1} max={10000} precision={0} />)}
                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>
        )
@@ -441,7 +473,7 @@
                  }
                ]
              })(
                <Radio.Group onChange={(e) => {this.onChange(e, item.key)}}>
                <Radio.Group onChange={(e) => {this.onChange(e, item.key)}} disabled={item.readonly}>
                  {
                    item.options.map(option => {
                      return (
@@ -477,7 +509,10 @@
          values.uuid = this.props.card.uuid
          values.verify = this.props.card.verify || null
          if (values.OpenType === 'excelIn' || values.OpenType === 'excelOut') {
          if (values.OpenType === 'excelIn') {
            values.position = 'toolbar'
            values.Ot = 'notRequired'
          } else if (values.OpenType === 'excelOut') {
            values.position = 'toolbar'
            values.Ot = 'notRequired'
          } else if (values.OpenType === 'popview' && !values.linkTab) { // 没有关联标签(新建时),创建新标签Id
src/templates/comtableconfig/index.jsx
@@ -23,6 +23,7 @@
import GridBtnForm from '@/templates/tableshare/gridbtnform'
import EditCard from '@/templates/tableshare/editcard'
import VerifyCard from '@/templates/tableshare/verifycard'
import VerifyCardExcelIn from '@/templates/tableshare/verifycardexcelin'
import MenuForm from '@/templates/tableshare/menuform'
import TabDragElement from '@/templates/tableshare/tabdragelement'
import SourceElement from '@/templates/tableshare/dragelement/source'
@@ -185,7 +186,8 @@
  componentDidMount () {
    let param = {
      func: 'sPC_Get_SelectedList',
      LText: 'select TbName ,Remark from sDataDictionary where IsKey!=\'\' and Deleted =0',
      // LText: 'select TbName ,Remark from sDataDictionary where IsKey!=\'\' and Deleted =0',
      LText: 'select TbName,Remark from (select TbName,Remark from sDataDictb where appkey= @appkey@ and Deleted=0 union select a.TbName,Remark from (select TbName,Remark from sDataDictb where appkey= \'\' and Deleted=0 ) a left join (select TbName from sDataDictb where appkey= @appkey@ and Deleted=0 ) b on a.TbName=b.TbName where b.TbName is null ) t',
      obj_name: 'data',
      arr_field: 'TbName,Remark'
    }
@@ -1282,6 +1284,53 @@
    const { card } = this.state
    let config = JSON.parse(JSON.stringify(this.state.config))
    let _verify = this.verifyRef.state.verify
    if (card.OpenType !== 'excelIn') {
      if (_verify.default === 'false' && _verify.scripts.length === 0) {
        notification.warning({
          top: 92,
          message: '不执行默认sql时,必须设置自定义脚本!',
          duration: 10
        })
        return
      }
    } else if (card.OpenType === 'excelIn') {
      let cols = _verify.columns.map(col => col.Column)
      cols = Array.from(new Set(cols))
      if (!_verify.sheet) {
        notification.warning({
          top: 92,
          message: '请设置导入表名!',
          duration: 10
        })
        return
      } else if (_verify.columns.length === 0) {
        notification.warning({
          top: 92,
          message: '请设置Excel列字段!',
          duration: 10
        })
        return
      } else if (_verify.columns.length > cols.length) {
        notification.warning({
          top: 92,
          message: 'Excel列字段名,不可重复!',
          duration: 10
        })
        return
      } else if (_verify.range === 1) {
        let tEmptys = _verify.columns.filter(op => !op.Text)
        if (tEmptys.length > 0) {
          notification.warning({
            top: 92,
            message: '忽略首行时,会使用Text值校验Excel首行内容,Text值与Excel表首行内容相同,且均不可为空!',
            duration: 10
          })
          return
        }
      }
    }
    config.action = config.action.map(item => {
      if (item.uuid === card.uuid) {
@@ -2495,7 +2544,7 @@
        <Modal
          title={modaltype === 'actionEdit' ? this.state.dict['header.modal.action.edit'] : this.state.dict['header.modal.action.copy']}
          visible={modaltype === 'actionEdit' || modaltype === 'actionCopy'}
          width={700}
          width={800}
          onCancel={this.editModalCancel}
          footer={[
            modaltype === 'actionEdit' ? <Button key="delete" className="mk-btn mk-purple" onClick={this.creatFunc} loading={this.state.funcLoading}>{this.state.dict['header.menu.func.create']}</Button> : null,
@@ -2612,7 +2661,21 @@
          onCancel={() => { this.setState({ profileVisible: false }) }}
          destroyOnClose
        >
          <VerifyCard card={this.state.card} columns={this.state.config.columns} wrappedComponentRef={(inst) => this.verifyRef = inst} dict={this.state.dict} />
          {this.state.card && this.state.card.OpenType !== 'excelIn' ?
            <VerifyCard
              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 === 'excelIn' ?
            <VerifyCardExcelIn
              card={this.state.card}
              dict={this.state.dict}
              wrappedComponentRef={(inst) => this.verifyRef = inst}
            /> : null
          }
        </Modal>
        {/* 设置全局配置及列表数据源 */}
        <Modal
src/templates/formtabconfig/editable/index.jsx
File was deleted
src/templates/formtabconfig/editable/index.scss
File was deleted
src/templates/formtabconfig/index.jsx
@@ -13,9 +13,10 @@
import Utils from '@/utils/utils.js'
import { getModalForm, getActionForm } from '@/templates/tableshare/formconfig'
import ModalForm from '@/templates/ushare/modalform'
import ActionForm from './actionform'
import SettingForm from './settingform'
import ModalForm from './modalform'
// import ModalForm from './modalform'
import DragElement from './dragelement'
import GroupForm from './groupform'
import TabForm from '@/templates/tableshare/tabform'
@@ -122,7 +123,8 @@
  componentDidMount () {
    let param = {
      func: 'sPC_Get_SelectedList',
      LText: 'select TbName ,Remark from sDataDictionary where IsKey!=\'\' and Deleted =0',
      // LText: 'select TbName ,Remark from sDataDictionary where IsKey!=\'\' and Deleted =0',
      LText: 'select TbName,Remark from (select TbName,Remark from sDataDictb where appkey= @appkey@ and Deleted=0 union select a.TbName,Remark from (select TbName,Remark from sDataDictb where appkey= \'\' and Deleted=0 ) a left join (select TbName from sDataDictb where appkey= @appkey@ and Deleted=0 ) b on a.TbName=b.TbName where b.TbName is null ) t',
      obj_name: 'data',
      arr_field: 'TbName,Remark'
    }
@@ -1210,7 +1212,7 @@
        func: 'sPC_Button_AddUpt',
        Type: 60,      // 添加按钮表单页下的按钮
        ParentID: menu.MenuID,
        MenuNo: res.menuNo,
        MenuNo: menu.MenuNo,
        Template: menu.PageParam.Template || '',
        PageParam: '',
        LongParam: '',
src/templates/formtabconfig/modalform/index.jsx
File was deleted
src/templates/formtabconfig/modalform/index.scss
File was deleted
src/templates/formtabconfig/settingform/index.jsx
@@ -4,7 +4,7 @@
import { formRule } from '@/utils/option.js'
import './index.scss'
// const { TextArea } = Input
const { TextArea } = Input
class SettingForm extends Component {
  static propTpyes = {
@@ -132,7 +132,7 @@
  }
  render() {
    const { dict, usefulFields } = this.props
    const { dict, usefulFields, menu } = this.props
    const { getFieldDecorator } = this.props.form
    const { interType, columns, selectTabs, setting } = this.state
@@ -256,7 +256,7 @@
              })(<Input placeholder="" autoComplete="off" />)}
            </Form.Item>
          </Col> : null}
          {/* {interType !== 'outer' ? <Col span={24}>
          {interType !== 'outer' ? <Col span={24}>
            <Form.Item help={'数据ID:' + menu.MenuID} label={
              <Tooltip placement="topLeft" title="使用系统函数时,需填写数据源,自定义函数时,可忽略。">
                <Icon type="question-circle" />
@@ -267,7 +267,7 @@
                initialValue: setting.dataresource
              })(<TextArea rows={4} />)}
            </Form.Item>
          </Col> : null} */}
          </Col> : null}
          {interType === 'outer' ? <Col span={12}>
            <Form.Item label={dict['header.form.outerFunc']}>
              {getFieldDecorator('outerFunc', {
src/templates/modalconfig/index.jsx
@@ -131,7 +131,8 @@
  componentDidMount () {
    let param = {
      func: 'sPC_Get_SelectedList',
      LText: 'select TbName ,Remark from sDataDictionary where IsKey!=\'\' and Deleted =0',
      // LText: 'select TbName ,Remark from sDataDictionary where IsKey!=\'\' and Deleted =0',
      LText: 'select TbName,Remark from (select TbName,Remark from sDataDictb where appkey= @appkey@ and Deleted=0 union select a.TbName,Remark from (select TbName,Remark from sDataDictb where appkey= \'\' and Deleted=0 ) a left join (select TbName from sDataDictb where appkey= @appkey@ and Deleted=0 ) b on a.TbName=b.TbName where b.TbName is null ) t',
      obj_name: 'data',
      arr_field: 'TbName,Remark'
    }
src/templates/subtableconfig/index.jsx
@@ -22,6 +22,7 @@
import GridBtnForm from '@/templates/tableshare/gridbtnform'
import EditCard from '@/templates/tableshare/editcard'
import VerifyCard from '@/templates/tableshare/verifycard'
import VerifyCardExcelIn from '@/templates/tableshare/verifycardexcelin'
import MenuForm from '@/templates/tableshare/menuform'
import SourceElement from '@/templates/tableshare/dragelement/source'
import Source from './source'
@@ -154,7 +155,8 @@
  componentDidMount () {
    let param = {
      func: 'sPC_Get_SelectedList',
      LText: 'select TbName ,Remark from sDataDictionary where IsKey!=\'\' and Deleted =0',
      // LText: 'select TbName ,Remark from sDataDictionary where IsKey!=\'\' and Deleted =0',
      LText: 'select TbName,Remark from (select TbName,Remark from sDataDictb where appkey= @appkey@ and Deleted=0 union select a.TbName,Remark from (select TbName,Remark from sDataDictb where appkey= \'\' and Deleted=0 ) a left join (select TbName from sDataDictb where appkey= @appkey@ and Deleted=0 ) b on a.TbName=b.TbName where b.TbName is null ) t',
      obj_name: 'data',
      arr_field: 'TbName,Remark'
    }
@@ -1123,6 +1125,53 @@
    let config = JSON.parse(JSON.stringify(this.state.config))
    let _verify = this.verifyRef.state.verify
    if (card.OpenType !== 'excelIn') {
      if (_verify.default === 'false' && _verify.scripts.length === 0) {
        notification.warning({
          top: 92,
          message: '不执行默认sql时,必须设置自定义脚本!',
          duration: 10
        })
        return
      }
    } else if (card.OpenType === 'excelIn') {
      let cols = _verify.columns.map(col => col.Column)
      cols = Array.from(new Set(cols))
      if (!_verify.sheet) {
        notification.warning({
          top: 92,
          message: '请设置导入表名!',
          duration: 10
        })
        return
      } else if (_verify.columns.length === 0) {
        notification.warning({
          top: 92,
          message: '请设置Excel列字段!',
          duration: 10
        })
        return
      } else if (_verify.columns.length > cols.length) {
        notification.warning({
          top: 92,
          message: 'Excel列字段名,不可重复!',
          duration: 10
        })
        return
      } else if (_verify.range === 1) {
        let tEmptys = _verify.columns.filter(op => !op.Text)
        if (tEmptys.length > 0) {
          notification.warning({
            top: 92,
            message: '忽略首行时,会使用Text值校验Excel首行内容,Text值与Excel表首行内容相同,且均不可为空!',
            duration: 10
          })
          return
        }
      }
    }
    config.action = config.action.map(item => {
      if (item.uuid === card.uuid) {
        item.verify = _verify
@@ -2167,7 +2216,22 @@
          onCancel={() => { this.setState({ profileVisible: false }) }}
          destroyOnClose
        >
          <VerifyCard floor="subtable" card={this.state.card} columns={this.state.config.columns} wrappedComponentRef={(inst) => this.verifyRef = inst} dict={this.state.dict} />
          {this.state.card && this.state.card.OpenType !== 'excelIn' ?
            <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.OpenType === 'excelIn' ?
            <VerifyCardExcelIn
              card={this.state.card}
              dict={this.state.dict}
              wrappedComponentRef={(inst) => this.verifyRef = inst}
            /> : null
          }
        </Modal>
        {/* 设置全局配置及列表数据源 */}
        <Modal
src/templates/tableshare/dragelement/card.jsx
@@ -148,7 +148,7 @@
      <Icon className="edit" title="编辑" type="edit" onClick={edit} />
      <Icon className="edit close" title="删除" type="close" onClick={del} />
      {type === 'action' ? <Icon className="edit copy" title="复制" type="copy" onClick={copy} /> : null}
      {type === 'action' && ['pop', 'prompt', 'exec'].includes(card.OpenType) && card.intertype === 'inner' && !card.innerFunc ?
      {type === 'action' && ['pop', 'prompt', 'exec', 'excelIn'].includes(card.OpenType) && card.intertype === 'inner' && !card.innerFunc ?
        <Icon className="edit profile" title="校验规则" type="profile" onClick={profile} /> : null
      }
    </div>
src/templates/tableshare/exceleditable/index.jsx
New file
@@ -0,0 +1,304 @@
import React, {Component} from 'react'
import { Table, Input, Button, Popconfirm, Form, Icon, InputNumber, Select } 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()
    })
  }
  typeChange = (key, val) => {
    const { record, handleSave } = this.props
    handleSave({ ...record, ...{[key]: val} })
    this.toggleEdit()
  }
  renderCell = form => {
    this.form = form
    const { children, dataIndex, record } = this.props
    const { editing } = this.state
    return editing ? (
      <div>
        {dataIndex === 'Column' || dataIndex === 'Text' ? <Form.Item style={{ margin: 0 }}>
          {form.getFieldDecorator(dataIndex, {
            initialValue: record[dataIndex],
            rules: [
              {
                required: dataIndex === 'Column',
                message: 'NOT NULL.',
              },
            ]
          })(<Input ref={node => (this.input = node)} autoComplete="off" onPressEnter={this.save} onBlur={this.save} />)}
        </Form.Item> : null}
        {dataIndex === 'min' || dataIndex === 'max' ? <Form.Item style={{ margin: 0 }}>
          {form.getFieldDecorator(dataIndex, {
            initialValue: record[dataIndex]
          })(<InputNumber ref={node => (this.input = node)} autoComplete="off" onPressEnter={this.save} onBlur={this.save} />)}
        </Form.Item> : null}
        {dataIndex === 'required' ? <Form.Item style={{ margin: 0 }}>
          {form.getFieldDecorator(dataIndex, {
            initialValue: record[dataIndex] || 'false'
          })(
            <Select
              onChange={(value) => {this.typeChange(dataIndex, value)}}
              onBlur={(value) => {this.typeChange(dataIndex, value)}}
              defaultOpen={true}
            >
              <Select.Option value='false'>否</Select.Option>
              <Select.Option value='true'>是</Select.Option>
            </Select>
          )}
        </Form.Item> : null}
        {dataIndex === 'type' ? <Form.Item style={{ margin: 0 }}>
          {form.getFieldDecorator(dataIndex, {
            initialValue: record[dataIndex] || 'text'
          })(
            <Select
              onChange={(value) => {this.typeChange(dataIndex, value)}}
              onBlur={(value) => {this.typeChange(dataIndex, value)}}
              defaultOpen={true}
            >
              <Select.Option value='text'>文本</Select.Option>
              <Select.Option value='number'>数值</Select.Option>
            </Select>
          )}
        </Form.Item> : null}
      </div>
    ) : (
      <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: 'Column',
        dataIndex: 'Column',
        width: '15%',
        editable: true
      },
      {
        title: 'Text',
        dataIndex: 'Text',
        width: '18%',
        editable: true
      },
      {
        title: '是否必填',
        dataIndex: 'required',
        width: '12%',
        editable: true,
        render: (text, record) => record.required === 'true' ? '是' : '否'
      },
      {
        title: '类型',
        dataIndex: 'type',
        width: '12%',
        editable: true,
        render: (text, record) => record.type === 'number' ? '数值' : '文本'
      },
      {
        title: '最小值',
        dataIndex: 'min',
        width: '13%',
        editable: true
      },
      {
        title: '最大值',
        dataIndex: 'max',
        width: '13%',
        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['header.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
    }
  }
  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 { dataSource } = this.state
    const newData = {
      key: Utils.getuuid(),
      Column: '',
      Text: ''
    }
    this.setState({
      dataSource: [...dataSource, newData]
    })
  }
  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 })
  }
  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-excel-edit-table">
        <Button onClick={this.handleAdd} type="primary" className="add-row">
          添加
        </Button>
        <Table
          components={components}
          rowClassName={() => 'editable-row'}
          bordered
          dataSource={dataSource}
          columns={columns}
          pagination={false}
        />
      </div>
    )
  }
}
export default EditTable
src/templates/tableshare/exceleditable/index.scss
New file
@@ -0,0 +1,49 @@
.common-excel-edit-table {
  margin-top: 30px;
  margin-left: -23px;
  margin-bottom: 15px;
  .add-row {
    position: absolute;
    z-index: 1;
    right: 12px;
    top: -10px;
  }
  .ant-table-thead > tr > th {
    padding: 10px 0px;
    text-align: center;
  }
  .ant-table-tbody > tr > td {
    padding: 0px 5px;
    .ant-input-number-input {
      padding: 0 3px;
    }
    .ant-input {
      padding: 0 3px;
    }
  }
  .editable-cell-value-wrap {
    cursor: pointer;
    height: 40px;
    width: 200px;
    display: table-cell;
    vertical-align: middle;
    word-wrap: break-word;
    word-break: break-word;
    .ant-input {
      height: 30px;
    }
  }
  .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;
  }
}
src/templates/tableshare/verifycard/customform/index.jsx
@@ -59,8 +59,15 @@
            duration: 10
          })
          return
        } else if (/--/ig.test(values.sql)) {
          notification.warning({
            top: 92,
            message: '自定义sql语句中,不可出现字符 -- ,注释请用 /*内容*/',
            duration: 10
          })
          return
        }
        this.props.customChange(values)
        this.setState({
          editItem: null
src/templates/tableshare/verifycard/customscript/index.jsx
@@ -55,6 +55,13 @@
            duration: 10
          })
          return
        } else if (/--/ig.test(values.sql)) {
          notification.warning({
            top: 92,
            message: '自定义sql语句中,不可出现字符 -- ,注释请用 /*内容*/',
            duration: 10
          })
          return
        }
        this.props.scriptsChange(values)
src/templates/tableshare/verifycard/index.jsx
@@ -363,6 +363,7 @@
    this.setState({
      verify: {
        ..._verify,
        default: _verify.default || 'true',
        invalid: _verify.invalid || 'false',
        uniques: _verify.uniques || [],
src/templates/tableshare/verifycardexcelin/columnform/index.jsx
New file
@@ -0,0 +1,168 @@
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,         // 字典项
    range: PropTypes.any,           // 字典项
    columnChange: PropTypes.func    // 修改函数
  }
  state = {
    editItem: null, // 编辑元素
    type: 'Nvarchar(50)'
  }
  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
    })
  }
  typeChange = (val) => {
    this.setState({
      type: val
    })
  }
  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: '',
          required: 'false',
          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: this.props.range === 1,
                    message: this.props.dict['form.required.input'] + 'Text!'
                  }
                ]
              })(<Input placeholder="" autoComplete="off" />)}
            </Form.Item>
          </Col>
          <Col span={7}>
            <Form.Item label={'是否必填'}>
              {getFieldDecorator('required', {
                initialValue: 'false'
              })(
                <Select>
                  <Select.Option value="false"> 否 </Select.Option>
                  <Select.Option value="true"> 是 </Select.Option>
                </Select>
              )}
            </Form.Item>
          </Col>
          <Col span={3} className="add">
            <Button onClick={this.handleConfirm} type="primary" className="add-row">
              确定
            </Button>
          </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>
          {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)
src/templates/tableshare/verifycardexcelin/columnform/index.scss
src/templates/tableshare/verifycardexcelin/customscript/index.jsx
New file
@@ -0,0 +1,126 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Input, Button, notification } from 'antd'
import './index.scss'
const { TextArea } = Input
class CustomForm extends Component {
  static propTpyes = {
    dict: PropTypes.object,         // 字典项
    usefulfields: PropTypes.string, // 可用字段
    scriptsChange: PropTypes.func   // 表单
  }
  state = {
    editItem: null
  }
  edit = (record) => {
    this.setState({
      editItem: record
    })
    this.props.form.setFieldsValue({
      sql: record.sql
    })
  }
  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: 10
          })
          return
        } else if (_lparen !== _rparen) {
          notification.warning({
            top: 92,
            message: 'sql中()必须成对出现',
            duration: 10
          })
          return
        } else if (/--/ig.test(values.sql)) {
          notification.warning({
            top: 92,
            message: '自定义sql语句中,不可出现字符 -- ,注释请用 /*内容*/',
            duration: 10
          })
          return
        }
        this.props.scriptsChange(values)
        this.setState({
          editItem: null
        })
        this.props.form.setFieldsValue({
          sql: ''
        })
      }
    })
  }
  render() {
    const { usefulfields } = this.props
    const { getFieldDecorator } = this.props.form
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
        sm: { span: 8 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 16 }
      }
    }
    let _fields = usefulfields.map(item => item.Column).join(', ')
    return (
      <Form {...formItemLayout} className="verify-form" id="verifycard2">
        <Row gutter={24}>
          {_fields ? <Col span={21} className="sqlfield">
            <Form.Item label={'可用字段'}>
              {_fields}
            </Form.Item>
          </Col> : null}
          <Col span={21} 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>
          <Col span={3} className="add">
            <Button onClick={this.handleConfirm} type="primary" className="add-row">
              确定
            </Button>
          </Col>
        </Row>
      </Form>
    )
  }
}
export default Form.create()(CustomForm)
src/templates/tableshare/verifycardexcelin/customscript/index.scss
src/templates/tableshare/verifycardexcelin/index.jsx
New file
@@ -0,0 +1,510 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Tabs, Row, Col, Input, Button, Table, Popconfirm, Icon, notification, Modal, message, InputNumber } from 'antd'
import { formRule } from '@/utils/option.js'
import Utils from '@/utils/utils.js'
import ColumnForm from './columnform'
import CustomScript from './customscript'
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: '16%',
        editable: true
      },
      {
        title: 'Text',
        dataIndex: 'Text',
        width: '19%',
        editable: true
      },
      {
        title: '是否必填',
        dataIndex: 'required',
        width: '12%',
        editable: true,
        render: (text, record) => record.required === 'true' ? '是' : '否'
      },
      {
        title: '类型',
        dataIndex: 'type',
        width: '12%',
        editable: 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['header.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']}
                cancelText={this.props.dict['header.cancel']}
                onConfirm={() => this.handleDelete(record, 'columns')
              }>
                <span style={{color: '#1890ff', cursor: 'pointer'}}><Icon type="delete" /></span>
              </Popconfirm>
            </div>
          )
      }
    ],
    scriptsColumns: [
      {
        title: 'SQL',
        dataIndex: 'sql',
        width: '70%'
      },
      {
        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['header.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']}
              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 || {}
    this.setState({
      verify: {
        ..._verify,
        sheet: _verify.sheet || '',
        range: _verify.range || 0,
        columns: _verify.columns || [],
        scripts: _verify.scripts || []
      }
    })
  }
  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
    })
  }
  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)
    }
    this.setState({ verify: verify })
  }
  handleEdit = (record, type) => {
    if (type === 'columns') {
      this.columnForm.edit(record)
    } else if (type === 'scripts') {
      this.scriptsForm.edit(record)
    }
    let node = document.getElementById('verify-excel-box-tab').parentNode
    if (node && node.scrollTop) {
      node.scrollTop = 0
    }
  }
  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
        }
      })
    }
    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 === '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
    })
  }
  sheetChange = (e) => {
    const { verify } = this.state
    this.setState({}, () => {
      this.props.form.validateFields(['sheet'], (errors, values) => {
        if (!errors) {
          this.setState({
            verify: {
              ...verify,
              ...values
            }
          })
        } else {
          this.setState({
            verify: {
              ...verify,
              sheet: ''
            }
          })
        }
      })
    })
  }
  rangeChange = (value) => {
    const { verify } = this.state
    this.setState({
      verify: {
        ...verify,
        range: value || 0
      }
    })
  }
  showError = (errorType) => {
    if (errorType === 'S') {
      notification.success({
        top: 92,
        message: '执行成功!',
        duration: 2
      })
    } else if (errorType === 'F') {
      notification.error({
        className: 'notification-custom-error',
        top: 92,
        message: '执行失败!',
        duration: 15
      })
    } else if (errorType === 'N') {
      notification.error({
        top: 92,
        message: '执行失败!',
        duration: 15
      })
    } 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 { getFieldDecorator } = this.props.form
    const { verify, excelColumns, scriptsColumns } = 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={this.props.dict['header.form.tablename']}>
                    {getFieldDecorator('sheet', {
                      initialValue: verify.sheet || '',
                      rules: [
                        {
                          required: true,
                          message: this.props.dict['form.required.input'] + this.props.dict['header.form.tablename'] + '!'
                        },
                        {
                          pattern: formRule.table.pattern,
                          message: formRule.table.message
                        }, {
                          max: formRule.table.max,
                          message: formRule.table.maxMessage
                        }
                      ]
                    })(<Input placeholder="" autoComplete="off" onChange={this.sheetChange} />)}
                  </Form.Item>
                </Col>
                <Col span={8}>
                  <Form.Item label={'忽略行'}>
                    <InputNumber min={0} max={100} precision={0} defaultValue={0} onChange={this.rangeChange} />
                  </Form.Item>
                </Col>
              </Row>
            </Form>
          </TabPane>
          <TabPane tab="Excel列设置" key="2x">
            <ColumnForm
              dict={this.props.dict}
              range={verify.range}
              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="6">
            <CustomScript
              usefulfields={verify.columns}
              dict={this.props.dict}
              scriptsChange={this.scriptsChange}
              wrappedComponentRef={(inst) => this.scriptsForm = inst}
            />
            <Table
              bordered
              rowKey="uuid"
              className="custom-table"
              dataSource={verify.scripts}
              columns={scriptsColumns}
              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={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"> -1 </span>
                    不提示
                  </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={15} 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={15} 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>
            </Form>
          </TabPane>
        </Tabs>
      </div>
    )
  }
}
export default Form.create()(VerifyCard)
src/templates/tableshare/verifycardexcelin/index.scss
New file
@@ -0,0 +1,53 @@
.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-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;
  }
}
src/templates/ushare/editable/index.jsx
@@ -22,7 +22,9 @@
  toggleEdit = () => {
    const editing = !this.state.editing
    this.setState({ editing }, () => {
      if (editing) {
      if (editing && this.input && this.input.select) {
        this.input.select()
      } else if (editing && this.input && this.input.focus) {
        this.input.focus()
      }
    })
@@ -99,7 +101,7 @@
    if (props.type === 'link') {
      _width = '27%'
    } else {
    } else if (props.type === 'select') {
      _width = Math.floor(80 / (props.linkSubFields.length + 2)) + '%'
      fields = props.linkSubFields.map(field => {
        return {
@@ -131,9 +133,18 @@
        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>
            <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['header.confirm']}
                cancelText={props.dict['header.cancel']}
                onConfirm={() => this.handleDelete(record.key)
              }>
                <span style={{color: '#1890ff', cursor: 'pointer'}}><Icon type="delete" /></span>
              </Popconfirm>
            </div>
          ) : null,
      }
    ]
@@ -154,6 +165,32 @@
      type: props.type,
      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 => {
@@ -192,18 +229,22 @@
    let dataSource = JSON.parse(JSON.stringify(this.state.dataSource))
    let _width = '40%'
    let fields = []
    console.log(linkSubFields)
    if (type === 'select' && linkSubFields.length > this.state.linkSubFields) {
      let addcol = linkSubFields[linkSubFields.length - 1]
      dataSource = dataSource.map(data => {
        data[addcol.field] = data.Text
        return data
      })
      console.log(addcol)
    }
    // console.log(linkSubFields)
    // console.log(type)
    // console.log(dataSource)
    if (type === 'link') {
      _width = '27%'
    } else {
    } else if (type === 'select') {
      _width = Math.floor(80 / (linkSubFields.length + 2)) + '%'
      fields = linkSubFields.map(field => {
        return {
@@ -214,6 +255,8 @@
        }
      })
    }
    console.log(fields)
    let columns = [
      {
@@ -235,9 +278,18 @@
        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>
            <div>
              <span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
              <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']}
                cancelText={this.props.dict['header.cancel']}
                onConfirm={() => this.handleDelete(record.key)
              }>
                <span style={{color: '#1890ff', cursor: 'pointer'}}><Icon type="delete" /></span>
              </Popconfirm>
            </div>
          ) : null,
      }
    ]
@@ -259,10 +311,8 @@
  }
  UNSAFE_componentWillReceiveProps (nextProps) {
    if (this.props.type !== nextProps.type) {
      this.resetColumn(nextProps.type)
    } else if (!is(fromJS(this.props.linkSubFields), fromJS(nextProps.linkSubFields))) {
      this.resetColumn(this.props.type, nextProps.linkSubFields)
    if (!is(fromJS(this.props.linkSubFields), fromJS(nextProps.linkSubFields)) || this.props.type !== nextProps.type) {
      this.resetColumn(nextProps.type, nextProps.linkSubFields)
    }
  }
src/templates/ushare/editable/index.scss
@@ -33,4 +33,8 @@
      margin: 0;
    }
  }
  .operation-btn {
    margin-right: 10px;
    cursor: pointer;
  }
}
src/templates/ushare/modalform/index.jsx
@@ -182,12 +182,18 @@
  multiselectChange = (key, value, options) => {
    if (key === 'linkSubField') {
      let arr = []
      let linkSubFields = options.filter(option => {
      let linkSubField = {}
      options.forEach(option => {
        if (!['Value', 'Text'].includes(option.field) && value.includes(option.field) && !arr.includes(option.field)) {
          arr.push(option.field)
          return true
        } else {
          return false
          linkSubField[option.field] = option
        }
      })
      let linkSubFields = []
      value.forEach(item => {
        if (linkSubField[item]) {
          linkSubFields.push(linkSubField[item])
        }
      })
@@ -415,7 +421,7 @@
      } else if (item.type === 'options') {
        fields.push(
          <Col span={20} offset={4} key={index}>
            <EditTable data={item.initVal} type={this.state.openType} linkSubFields={this.state.linkSubFields} ref="editTable"/>
            <EditTable data={item.initVal} dict={this.props.dict} type={this.state.openType} linkSubFields={this.state.linkSubFields} ref="editTable"/>
          </Col>
        )
      }
src/utils/option.js
@@ -24,6 +24,12 @@
    innerPattern: '[0-9a-zA-Z_]*',
    innerMessage: '内部函数名称只允许包含数字、字母和下划线,且以指定字符开始。'
  },
  table: { // 函数名
    max: 100,
    pattern: /^[0-9a-zA-Z_]*$/,
    message: '表名只允许包含数字、字母和下划线。',
    maxMessage: '表名不超过100个字符。'
  },
  textarea: {
    max: 1024,
    message: '长文本最多1024个字符。'
src/utils/utils.js
@@ -441,6 +441,131 @@
  }
  /**
   * @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 _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, '')
          let limitlen = col.type.match(/\d+/)[0]
          if (!val && col.required === 'true') { // 必填校验
            let _error =  _position + dict['main.excel.content.emptyerror']
            errors.push(_error)
          } else if (val.length > limitlen) {    // 长度校验
            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 (typeof(val) !== 'number' || parseInt(val) < parseFloat(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)) {
          let _val = val + ''
          _val = _val.split('.')
          let limitlen = col.type.match(/\d+/ig)[1]
          if (typeof(val) !== 'number') {                           // 检验是否为浮点数
            let _error = _position + dict['main.excel.content.floaterror']
            errors.push(_error)
          } else if (_val[0].length > 18) {                         // 检验整数位
            let _error = _position + dict['main.excel.content.floatIntover']
            errors.push(_error)
          } else if (_val[1] && _val[1].length > limitlen) {        // 最小值检验
            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}`
      })
      if (!item.innerFunc) {
        vals.push(`@upid+'${this.getuuid()}' as jskey`)
      }
      return `Select ${vals.join(',')}`
    })
    _Ltext = _Ltext.join(' Union all ')
    let _sql = ''
    if (!item.innerFunc) {
      let declarefields = []
      let fields = []
      let timestamp = new Date().getTime()
      btn.columns.forEach(col => {
        declarefields.push(`${col.Column} ${col.type}`)
        fields.push(col.Column)
      })
      fields = fields.join(',')
      _sql = `declare @${btn.sheet} table (${declarefields.join(',')},jskey nvarchar(50) )
      Declare @UserName nvarchar(50),@FullName nvarchar(50) ,@upid nvarchar(50)
      select @UserName=UserName,@FullName=FullName from SUsers where UID=@UserID@
      set @upid='${timestamp}'
      Insert into  @${btn.sheet} (${fields},jskey)
      ${_Ltext}
      Insert into ${btn.sheet} (${fields},createuserid,createuser,createstaff,bid,upid)
      Select ${fields},@userid@,@username,@fullname,@BID@,@upid From @${btn.sheet}
      Delete @${btn.sheet}`
    } else {
      _sql = _Ltext
    }
    console.log(_sql)
    return {
      sql: _sql,
      errors: errors.join('; ')
    }
  }
  /**
   * @description 使用系统函数时(sPC_TableData_InUpDe ),生成sql语句
   * @return {String} type   执行类型
   * @return {String} table  表名
@@ -552,10 +677,10 @@
        `
    }
    // 添加时主键为空
    if (btn.sqlType === 'insert') {
      primaryId = ''
    }
    // 添加时主键为空 改为前台生成
    // if (btn.sqlType === 'insert') {
    //   primaryId = ''
    // }
    // 去除禁用的验证
    if (verify.contrasts) {
@@ -759,6 +884,10 @@
        }
      })
      if (!keys.includes(primaryKey)) {
        keys.push(primaryKey)
        values.push('\'' + primaryId + '\'')
      }
      if (!keys.includes('createuserid')) {
        keys.push('createuserid')
        values.push('@userid@')