king
2022-12-19 102be577a7f8df2ae30045d55a1a5fc584f90363
src/templates/sharecomponent/actioncomponent/verifyprint/index.jsx
@@ -1,16 +1,25 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Tabs, Row, Col, Button, notification, Modal, message, InputNumber, Input, Select, Radio, Tooltip } from 'antd'
import { QuestionCircleOutlined } from '@ant-design/icons'
import { fromJS } from 'immutable'
import { Form, Tabs, Row, Col, Button, notification, Modal, message, InputNumber, Input, Select, Radio, Tooltip, Typography, Popconfirm, Spin } from 'antd'
import { QuestionCircleOutlined, EditOutlined, StopOutlined, CheckCircleOutlined, SwapOutlined, DeleteOutlined } from '@ant-design/icons'
import moment from 'moment'
import Api from '@/api'
import Utils from '@/utils/utils.js'
import SettingUtils from './utils.jsx'
import CodeMirror from '@/templates/zshare/codemirror'
import DataSource from '../verifyexcelout/datasource'
import CustomScript from '../verifyexcelout/customscript'
import asyncComponent from '@/utils/asyncComponent'
import ColForm from '@/menu/datasource/verifycard/columnform'
import EditTable from './editable'
import './index.scss'
const EditMTable = asyncComponent(() => import('@/templates/zshare/editTable'))
const FieldsComponent = asyncComponent(() => import('@/templates/sharecomponent/fieldscomponent'))
const { Paragraph } = Typography
const { TabPane } = Tabs
class VerifyCard extends Component {
@@ -25,20 +34,239 @@
  state = {
    verify: {},
    templates: [],
    loading: false,
    activeKey: 'base',
    selectimg: '',
    printMode: 'normal'
    dataType: 'line',
    printMode: 'normal',
    usefulfields: '',
    declareSql: '',
    scriptsColumns: [
      {
        title: 'SQL',
        dataIndex: 'sql',
        width: '60%',
        render: (text) => {
          let title = text.match(/^\s*\/\*.+\*\//)
          title = title && title[0] ? title[0] : ''
          let _text = title ? text.replace(title, '') : text
          return (
            <div>
              {title ? <span style={{color: '#a50'}}>{title}<span style={{fontSize: '12px', marginLeft: '5px'}}>{_text.length}</span></span> : null}
              <Paragraph copyable={{ text: text }} ellipsis={{ rows: 4, expandable: true }}>{_text}</Paragraph>
            </div>
          )
        }
      },
      {
        title: '执行位置',
        dataIndex: 'position',
        width: '10%',
        render: (text, record) => {
          if (record.position === 'init') {
            return <span style={{color: 'orange'}}>初始化</span>
          } else if (record.position === 'front') {
            return <span style={{color: '#26C281'}}>sql前</span>
          } else {
            return <span style={{color: '#1890ff'}}>sql后</span>
          }
        }
      },
      {
        title: '状态',
        dataIndex: 'status',
        width: '10%',
        render: (text, record) => record.status === 'false' ?
          (
            <div style={{color: '#ff4d4f'}}>
              禁用
              <StopOutlined style={{marginLeft: '5px'}} />
            </div>
          ) :
          (
            <div style={{color: '#26C281'}}>
              启用
              <CheckCircleOutlined style={{marginLeft: '5px'}}/>
            </div>
          )
      },
      {
        title: '操作',
        align: 'center',
        width: '140px',
        dataIndex: 'operation',
        render: (text, record) =>
          (<div style={{textAlign: 'center'}}>
            <span className="operation-btn" title="编辑" onClick={() => this.handleEdit(record, 'scripts')} style={{color: '#1890ff'}}><EditOutlined /></span>
            <span className="operation-btn" title="状态切换" onClick={() => this.handleStatus(record, 'scripts')} style={{color: '#8E44AD'}}><SwapOutlined /></span>
            <Popconfirm
              overlayClassName="popover-confirm"
              title="确定删除吗?"
              onConfirm={() => this.handleDelete(record, 'scripts')
            }>
              <span className="operation-btn" style={{color: '#ff4d4f'}}><DeleteOutlined /></span>
            </Popconfirm>
          </div>)
      }
    ],
    colColumns: [
      {
        title: '名称',
        dataIndex: 'label',
        inputType: 'input',
        editable: true,
        width: '28%'
      },
      {
        title: '字段',
        dataIndex: 'field',
        inputType: 'input',
        editable: true,
        unique: true,
        copy: true,
        rules: [{
          pattern: /^[\u4E00-\u9FA50-9a-zA-Z_]*$/ig,
          message: '字段名只允许包含数字、字母、汉字以及_'
        }],
        width: '28%'
      },
      {
        title: '数据类型',
        dataIndex: 'datatype',
        inputType: 'select',
        options: [
          { value: 'Nvarchar(10)', text: 'Nvarchar(10)' },
          { value: 'Nvarchar(20)', text: 'Nvarchar(20)' },
          { value: 'Nvarchar(50)', text: 'Nvarchar(50)' },
          { value: 'Nvarchar(100)', text: 'Nvarchar(100)' },
          { value: 'Nvarchar(256)', text: 'Nvarchar(256)' },
          { value: 'Nvarchar(512)', text: 'Nvarchar(512)' },
          { value: 'Nvarchar(1024)', text: 'Nvarchar(1024)' },
          { value: 'Nvarchar(2048)', text: 'Nvarchar(2048)' },
          { value: 'Nvarchar(max)', text: 'Nvarchar(max)' },
          { value: 'Int', text: 'Int' },
          { value: 'Decimal(18,0)', text: 'Decimal(18,0)' },
          { value: 'Decimal(18,1)', text: 'Decimal(18,1)' },
          { value: 'Decimal(18,2)', text: 'Decimal(18,2)' },
          { value: 'Decimal(18,3)', text: 'Decimal(18,3)' },
          { value: 'Decimal(18,4)', text: 'Decimal(18,4)' },
          { value: 'Decimal(18,5)', text: 'Decimal(18,5)' },
          { value: 'Decimal(18,6)', text: 'Decimal(18,6)' },
          { value: 'Decimal(18,7)', text: 'Decimal(18,7)' },
          { value: 'Decimal(18,8)', text: 'Decimal(18,8)' },
          { value: 'Decimal(18,9)', text: 'Decimal(18,9)' },
          { value: 'Decimal(18,10)', text: 'Decimal(18,10)' },
          { value: 'Decimal(18,11)', text: 'Decimal(18,11)' },
          { value: 'Decimal(18,12)', text: 'Decimal(18,12)' },
          { value: 'Decimal(18,13)', text: 'Decimal(18,13)' },
          { value: 'Decimal(18,14)', text: 'Decimal(18,14)' },
          { value: 'Decimal(18,15)', text: 'Decimal(18,15)' },
          { value: 'Decimal(18,16)', text: 'Decimal(18,16)' },
          { value: 'Decimal(18,17)', text: 'Decimal(18,17)' },
          { value: 'Decimal(18,18)', text: 'Decimal(18,18)' },
          { value: 'date', text: 'date' },
          { value: 'datetime', text: 'datetime' },
        ],
        editable: true,
        width: '25%',
      }
    ]
  }
  UNSAFE_componentWillMount() {
    let _verify = this.props.card.verify || {}
    const { columns, card } = this.props
    let _verify = fromJS(card.verify || {}).toJS()
    _verify.Template = _verify.Template || ''
    _verify.printerTypeList = _verify.printerTypeList || []
    _verify.linkType = _verify.linkType || 'system'
    _verify.printMode = _verify.printMode || 'normal'
    _verify.scripts = _verify.scripts || []
    _verify.columns = _verify.columns || []
    let _usefulfields = []
    let _declare = []
    let _select = []
    let fieldArr = []
    let _sql = ''
    if (card.execMode === 'pop' && card.modal && card.modal.fields) {
      card.modal.fields.forEach(_f => {
        if (!_f.field || fieldArr.includes(_f.field.toLowerCase())) return
        fieldArr.push(_f.field.toLowerCase())
        _usefulfields.push(_f.field)
        let _fieldlen = _f.fieldlength || 50
        if (_f.type === 'number') {
          _fieldlen = _f.decimal ? _f.decimal : 0
        }
        if (_fieldlen > 2048) {
          _fieldlen = 'max'
        }
        let _type = `nvarchar(${_fieldlen})`
        if (_f.type.match(/date/ig)) {
          _type = 'datetime'
          _select.push(`@${_f.field}='1949-10-01'`)
        } else if (_f.type === 'number') {
          _type = `decimal(18,${_fieldlen})`
          _select.push(`@${_f.field}=0`)
        } else if (_f.type === 'rate') {
          _type = `decimal(18,2)`
          _select.push(`@${_f.field}=0`)
        } else {
          _select.push(`@${_f.field}=''`)
        }
        _declare.push(`@${_f.field} ${_type}`)
      })
      if (_declare.length > 0) {
        _sql = `/* 表单变量 */
          Declare ${_declare.join(', ')}
          Select ${_select.join(', ')}
        `
      }
      _declare = []
      _select = []
    }
    if (columns && columns.length > 0 && card.Ot !== 'notRequired') {
      columns.forEach(_f => {
        if (!_f.field || fieldArr.includes(_f.field.toLowerCase()) || !_f.datatype) return
        fieldArr.push(_f.field.toLowerCase())
        _usefulfields.push(_f.field)
        if (/decimal/ig.test(_f.datatype)) {
          _select.push(`@${_f.field}=0`)
        } else {
          _select.push(`@${_f.field}=''`)
        }
        _declare.push(`@${_f.field} ${_f.datatype}`)
      })
      if (_declare.length > 0) {
        _sql += `/* 显示列变量 */
          Declare ${_declare.join(', ')}
          Select ${_select.join(', ')}
        `
      }
    }
    this.setState({
      verify: _verify,
      declareSql: _sql,
      usefulfields: _usefulfields.join(', '),
      dataType: _verify.dataType || 'line',
      linkType: _verify.linkType,
      printMode: _verify.printMode,
      printFunc: _verify.printFunc || '// Function(data, form, printer, notification) data-打印数据列表,form-表单信息(不存在时为{}),printer-打印设置,notification-信息提示控件'
@@ -157,56 +385,67 @@
  }
  handleConfirm = () => {
    const { verify } = this.state
    const { verify, activeKey } = this.state
    // 表单提交时检查输入值是否正确
    return new Promise((resolve, reject) => {
      this.props.form.validateFieldsAndScroll((err, values) => {
        if (!err) {
          let _verify = {...verify, ...values}
          if (this.refs.editTable && this.refs.editTable.state) {
            let printTypes = this.refs.editTable.state.dataSource
      if (activeKey === 'base') {
        this.props.form.validateFieldsAndScroll((err, values) => {
          if (err) return
  
            let emptys = printTypes.filter(item => !item.Value || !item.Text)
            let valMap = new Map()
            let isvalid = true
          resolve({...verify, ...values})
        })
      } else if (activeKey === 'print') {
        if (verify.printerTypeList.length > 0) {
          let printTypes = verify.printerTypeList.map(item => item.Value)
          printTypes = Array.from(new Set(printTypes))
  
            printTypes.forEach(item => {
              if (valMap.has(item.Value)) {
                isvalid = false
              } else {
                valMap.set(item.Value, item.Text)
              }
          if (verify.printerTypeList.length > printTypes.length) {
            notification.warning({
              top: 92,
              message: '打印类型中Value字段不可重复!',
              duration: 5
            })
            if (emptys.length > 0) {
              notification.warning({
                top: 92,
                message: '打印类型表格中Value、Text字段不可为空!',
                duration: 5
              })
              return
            } else if (!isvalid) {
              notification.warning({
                top: 92,
                message: '打印类型表格中Value字段不可重复!',
                duration: 5
              })
              return
            }
            _verify.printerTypeList = printTypes
            return
          }
          resolve(_verify)
        } else {
        }
        resolve(verify)
      } else if (activeKey === 'setting') {
        this.settingForm.handleConfirm().then(res => {
          let _verify = {...verify, setting: res}
          this.setState({
            verify: _verify
          }, () => {
            this.setState({loading: true})
            this.sqlverify(() => { // 验证成功
              resolve(_verify)
            }, () => {             // 验证失败
              this.setState({
                loading: false
              })
            }, _verify.scripts)
          })
        })
      } else if (activeKey === 'scripts') {
        if (this.scriptsForm && this.scriptsForm.props.form.getFieldValue('sql') && !/^\s+$/.test(this.scriptsForm.props.form.getFieldValue('sql'))) {
          notification.warning({
            top: 92,
            message: '链接地址与打印模板不可为空!',
            message: '存在未保存脚本,请点击确定保存,或点击取消放弃修改!',
            duration: 5
          })
          return
        }
      })
        this.setState({loading: true})
        this.sqlverify(() => { // 验证成功
          resolve(verify)
        }, () => {             // 验证失败
          this.setState({
            loading: false
          })
        }, verify.scripts)
      } else {
        resolve(verify)
      }
    })
  }
@@ -254,10 +493,182 @@
    })
  }
  changeDataType = (e) => {
    let value = e.target.value
    this.setState({
      dataType: value
    })
  }
  // 标签切换
  tabchange = (val) => {
    const { activeKey, verify } = this.state
    if (activeKey === 'base') {
      this.props.form.validateFieldsAndScroll((err, values) => {
        if (err) return
        this.setState({
          verify: {...verify, ...values},
          activeKey: val
        })
      })
    } else if (activeKey === 'print') {
      if (verify.printerTypeList.length > 0) {
        let printTypes = verify.printerTypeList.map(item => item.Value)
        printTypes = Array.from(new Set(printTypes))
        if (verify.printerTypeList.length > printTypes.length) {
          notification.warning({
            top: 92,
            message: '打印类型中Value字段不可重复!',
            duration: 5
          })
          return
        }
      }
      this.setState({
        activeKey: val
      })
    } else if (activeKey === 'setting') {
      this.settingForm.handleConfirm().then(res => {
        this.setState({
          verify: {...verify, setting: res}
        }, () => {
          this.setState({loading: true})
          this.sqlverify(() => { // 验证成功
            this.setState({
              activeKey: val,
              loading: false
            })
          }, () => {             // 验证失败
            this.setState({
              activeKey: val,
              loading: false
            })
          }, verify.scripts)
        })
      })
    } else if (activeKey === 'scripts') {
      if (this.scriptsForm && this.scriptsForm.props.form.getFieldValue('sql') && !/^\s+$/.test(this.scriptsForm.props.form.getFieldValue('sql'))) {
        notification.warning({
          top: 92,
          message: '存在未保存脚本,请点击确定保存,或点击取消放弃修改!',
          duration: 5
        })
        return
      }
      this.setState({loading: true})
      this.sqlverify(() => { // 验证成功
        this.setState({
          activeKey: val,
          loading: false
        })
      }, () => {             // 验证失败
        this.setState({
          activeKey: val,
          loading: false
        })
      }, verify.scripts)
    } else {
      this.setState({
        activeKey: val
      })
    }
  }
  scriptsChange = (values, callback) => {
    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({loading: true})
    this.sqlverify(() => { // 验证成功
      this.setState({
        loading: false,
        verify: verify
      })
      callback(true)
    }, () => {             // 验证失败
      this.setState({
        loading: false
      })
      callback(false)
    }, verify.scripts)
  }
  sqlverify = (_resolve, _reject, scripts) => {
    const { verify, declareSql } = this.state
    let timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
    let sql = SettingUtils.getDebugSql(verify.setting || {}, verify.columns, scripts, declareSql, timestamp)
    let param = {
      func: 's_debug_sql',
      exec_type: 'y',
      LText: sql
    }
    param.LText = Utils.formatOptions(param.LText)
    param.timestamp = timestamp
    param.secretkey = Utils.encrypt('', timestamp)
    Api.genericInterface(param).then(result => {
      if (result.status) {
        _resolve()
      } else {
        _reject()
        Modal.error({
          title: result.message
        })
      }
    })
  }
  columnChange = (values, resolve) => {
    let verify = fromJS(this.state.verify).toJS()
    let fields = verify.columns.map(item => item.field.toLowerCase())
    if (fields.includes(values.field.toLowerCase())) {
      notification.warning({
        top: 92,
        message: '字段已存在!',
        duration: 5
      })
      return
    }
    resolve()
    values.uuid = Utils.getuuid()
    verify.columns.push(values)
    this.setState({verify})
  }
  updatefields = (columns) => {
    let verify = fromJS(this.state.verify).toJS()
    verify.columns = columns
    this.setState({verify})
  }
  render() {
    const { card } = this.props
    const { getFieldDecorator } = this.props.form
    const { verify, linkType, printMode, printFunc } = this.state
    const { verify, linkType, printMode, printFunc, scriptsColumns, dataType, loading, activeKey, usefulfields, colColumns } = this.state
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
@@ -270,10 +681,11 @@
    }
    return (
      <div>
      <div className="verify-card-print-box">
        {card.label ? <div className="mk-com-name">{card.label} - 验证信息</div> : null}
        <Tabs defaultActiveKey="1" className="verify-card-print-box" onChange={this.tabchange}>
          <TabPane tab="打印验证" key="1">
        {loading && <Spin size="large" />}
        <Tabs activeKey={activeKey} onChange={this.tabchange}>
          <TabPane tab="打印验证" key="base">
            <Form {...formItemLayout}>
              <Row gutter={24}>
                <Col span={8}>
@@ -339,6 +751,18 @@
                    })(<Input placeholder="" autoComplete="off" />)}
                  </Form.Item>
                </Col>}
                {card.intertype === 'system' ? <Col span={8}>
                  <Form.Item label="数据类型">
                    {getFieldDecorator('dataType', {
                      initialValue: dataType || 'line'
                    })(
                      <Radio.Group onChange={this.changeDataType}>
                        <Radio value="line">行数据</Radio>
                        <Radio value="custom">自定义</Radio>
                      </Radio.Group>
                    )}
                  </Form.Item>
                </Col> : null}
                {printMode === 'custom' ? <Col span={24}>
                  <Form.Item label={'处理函数'} className="printFunc">
                    {getFieldDecorator('printFunc', {
@@ -433,7 +857,7 @@
                    )}
                  </Form.Item>
                </Col> : null}
                {printMode !== 'custom' ? <Col span={8} offset={printMode === 'RFID' ? 16 : 0}>
                {printMode !== 'custom' ? <Col span={8} offset={16}>
                  <img className="legend" src={this.state.selectimg} alt=""/>
                </Col> : null }
              </Row>
@@ -444,7 +868,7 @@
              打印类型
              {verify.printerTypeList.length ? <span className="count-tip">{verify.printerTypeList.length}</span> : null}
            </span>
          } disabled={printMode === 'RFID'} key="2">
          } disabled={printMode === 'RFID'} key="print">
            <Form {...formItemLayout}>
              <Row gutter={24}>
                <Col span={24} className="print-tip">
@@ -455,12 +879,45 @@
                  </Form.Item>
                </Col>
                <Col span={24}>
                  <EditTable data={verify.printerTypeList} ref="editTable"/>
                  <EditTable data={verify.printerTypeList} onChange={(list) => this.setState({verify: {...verify, printerTypeList: list}})}/>
                </Col>
              </Row>
            </Form>
          </TabPane>
          <TabPane tab="信息提示" key="7">
          {card.intertype === 'system' ? <TabPane tab="数据源" disabled={dataType !== 'custom'} key="setting">
            <DataSource setting={verify.setting || {}} btnType="print" wrappedComponentRef={(inst) => this.settingForm = inst}/>
          </TabPane> : null}
          {card.intertype === 'system' ? <TabPane tab={
            <span>
              字段集
              {verify.columns.length ? <span className="count-tip">{verify.columns.length}</span> : null}
            </span>
          } key="columns">
            <ColForm columnChange={this.columnChange}/>
            <FieldsComponent
              config={verify}
              type="fields"
              updatefield={this.updatefields}
            />
            <EditMTable actions={['edit', 'move', 'copy', 'del', 'clear']} type="datasourcefield" data={verify.columns} columns={colColumns} onChange={(columns) => this.setState({verify: {...verify, columns}})}/>
          </TabPane> : null}
          {card.intertype === 'system' ? <TabPane tab={
            <span>
              自定义脚本
              {verify.scripts.length ? <span className="count-tip">{verify.scripts.length}</span> : null}
            </span>
          } key="scripts" disabled={dataType !== 'custom'} id="mk-exout-script">
            <CustomScript
              btn={card}
              sheet={verify.setting ? verify.setting.tableName : ''}
              searches={[]}
              linefields={usefulfields}
              scriptsChange={this.scriptsChange}
              wrappedComponentRef={(inst) => this.scriptsForm = inst}
            />
            <EditMTable actions={['move']} data={verify.scripts} columns={scriptsColumns} onChange={(scripts) => {this.setState({verify: {...verify, scripts}})}}/>
          </TabPane> : null}
          <TabPane tab="信息提示" key="message">
            <div style={{textAlign: 'center', fontSize: '13px', marginBottom: '10px'}}>打印信息中如果存在网络资源(图片),请确保资源可以正常访问,资源不存在时会报数据异常。</div>
            <Form {...formItemLayout}>
              <Row gutter={24}>