king
2025-04-23 b48528b1a1a88e289fc0b7ad52f2da213a3f9dfe
src/tabviews/custom/components/module/invoice/index.jsx
@@ -2,8 +2,9 @@
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Select, Form, Input, Button, Modal, Spin, notification } from 'antd'
import { EllipsisOutlined } from '@ant-design/icons'
import { EllipsisOutlined, LeftOutlined } from '@ant-design/icons'
import moment from 'moment'
import md5 from 'md5'
import Api from '@/api'
import UtilsDM from '@/utils/utils-datamanage.js'
@@ -20,15 +21,11 @@
  state = {
    BID: '',
    invTypes: [
      {value: '1', label: '电子发票(增值税专用发票)'},
      {value: '2', label: '电子发票(普通发票)'},
      {value: '3', label: '增值税纸质专用发票'},
      {value: '4', label: '增值税纸质普通发票'},
      {value: '5', label: '增值税电子普通发票'},
      {value: '6', label: '增值税电子专用发票'},
    ],
    ID: Utils.getguid(),
    io: '',
    invTypes: [],
    invoice_type: '',
    business_type: '',
    date: moment().format('YYYY年MM月DD日'),
    from_to_name: '',
    from_to_tax_no: '',
@@ -50,12 +47,19 @@
    reviewer: '',
    drawer: '',
    details: [],
    oriDetails: [],
    book: null,
    loading: false,
    saveType: '',
    tax_type: '',
    reqfields: [],
    requireds: []
    requireds: [],
    invoice_no: '',
    invoice_code: '',
    invoice_date: '',
    read_only: false,
    invoice_type_name: '',
    timestamp: ''
  }
  UNSAFE_componentWillMount () {
@@ -80,6 +84,13 @@
    _config.buyer = this.formatSetting(_config.buyer, 'buyer')
    _config.detail = this.formatSetting(_config.detail, 'detail')
    _config.detail.uuid = _config.uuid
    _config.buyer.setting.uuid = _config.uuid + 'buyer'
    _config.detail.setting.uuid = _config.uuid + 'detail'
    _config.billOutBtn.uuid = _config.uuid
    _config.billSaveBtn.uuid = _config.uuid
    _config.billOutBtn.logLabel = _config.$menuname + '-' + _config.billOutBtn.label
    _config.billSaveBtn.logLabel = _config.$menuname + '-' + _config.billSaveBtn.label
    let book = null
    let pas = {}
@@ -131,12 +142,21 @@
    item.setting.arr_field = item.columns.map(col => col.field).join(',')
    item.setting.laypage = item.setting.laypage === 'true'
    if (item.refreshTab && item.refreshTab.length) {
      item.reTabId = item.refreshTab.pop()
    }
    if (item.syncComponent && item.syncComponent.length) {
      item.syncComId = item.syncComponent.pop()
    }
    if (type === 'buyer') {
      item.columns = item.columns.map(cell => {
        if (['from_to_tel', 'from_to_account_no', 'from_to_code'].includes(cell.field)) {
          cell.Hide = 'true'
        } else if (['from_to_email', 'from_to_mob'].includes(cell.field)) {
          cell.Width = 80
        } else if (['from_to_name'].includes(cell.field)) {
          cell.Width = 140
        }
        return cell
      })
@@ -146,7 +166,7 @@
          cell.field = 'tax_rate'
          cell.label = '税率'
        }
        if (['Description', 'id', 'small_tax_rate'].includes(cell.field)) {
        if (['Description', 'id', 'small_tax_rate', 'free_tax_mark', 'vat_special_management', 'tax_item', 'tax_method'].includes(cell.field)) {
          cell.Hide = 'true'
        } else if (['spec'].includes(cell.field)) {
          cell.Width = 150
@@ -196,9 +216,6 @@
    if (!item.setting.execute) {
      item.setting.dataresource = ''
    }
    if (/\s/.test(item.setting.dataresource)) {
      item.setting.dataresource = '(' + item.setting.dataresource + ') tb'
    }
    if (sessionStorage.getItem('dataM') === 'true') { // 数据权限
      item.setting.dataresource = item.setting.dataresource.replace(/\$@/ig, '/*').replace(/@\$/ig, '*/').replace(/@datam@/ig, '\'Y\'')
@@ -218,8 +235,17 @@
    item.setting.customScript = _customScript // 整理后自定义脚本
    item.setting.tailScript = _tailScript     // 后置自定义脚本
    item.setting.custompage = false
    if (/order\s+by\s+sort_id\s*$/i.test(item.setting.dataresource)) {
      item.setting.custompage = true
    } else if (/@pageSize@|@orderBy@|@mk_total/i.test(item.setting.dataresource + item.setting.customScript)) {
      item.setting.custompage = true
    }
    item.setting.custompage = /@pageSize@|@orderBy@/i.test(item.setting.dataresource + item.setting.customScript)
    if (/\s/.test(item.setting.dataresource)) {
      item.setting.dataresource = '(' + item.setting.dataresource + ') tb'
    }
    return item
  }
@@ -278,9 +304,13 @@
  }
  async loadData() {
    const { config, BID } = this.state
    const { config, BID, book } = this.state
    if (config.wrap.datatype !== 'dynamic') return
    if (config.wrap.datatype !== 'dynamic' || !book) return
    if (!BID) {
      this.clearData()
      return
    }
    let param = UtilsDM.getQueryDataParams(config.setting, [], config.setting.order, 1, 1, BID)
@@ -290,10 +320,91 @@
    let result = await Api.genericInterface(param)
    if (result.status) {
      if (!result.data[0]) {
        this.clearData()
        this.setState({
          loading: false
        })
        return
      }
      let line = result.data[0]
      let details = result.data.map(item => {
        let tax_name = item.tax_rate * 100 + '%'
        if (item.vat_special_management && item.free_tax_mark === 'true') {
          tax_name = item.vat_special_management
        }
        return {
          uuid: item.jskey,
          productname: item.productname,
          productcode: item.productcode,
          spec: item.spec,
          unit: item.unit,
          bill_count: item.bill_count,
          unitprice: item.unitprice,
          tax_rate: item.tax_rate,
          free_tax_mark: item.free_tax_mark,
          vat_special_management: item.vat_special_management,
          tax_classify_code: item.tax_classify_code,
          tax_classify_name: item.tax_classify_name,
          amount_line: item.amount_line,
          tax_amount: item.tax_amount,
          invoice_lp: item.invoice_lp,
          tax_item: item.tax_item,
          tax_method: item.tax_method,
          tax_name: tax_name
        }
      })
      let invoice_type_name = ''
      if (line.read_only === 'true') {
        let types = book.invoice_type || []
        types.forEach(item => {
          if (item.value === line.invoice_type) {
            invoice_type_name = item.label
          }
        })
        invoice_type_name = invoice_type_name || line.invoice_type
      }
      this.setState({
        ID: line[config.setting.primaryKey] || Utils.getguid(),
        io: line.io,
        invoice_type: line.invoice_type,
        business_type: line.business_type,
        from_to_name: line.from_to_name,
        from_to_tax_no: line.from_to_tax_no,
        from_to_addr: line.from_to_addr,
        from_to_tel: line.from_to_tel,
        from_to_bank_name: line.from_to_bank_name,
        from_to_account_no: line.from_to_account_no,
        from_to_mob: line.from_to_mob,
        from_to_email: line.from_to_email,
        from_to_code: line.from_to_code,
        orgname: line.orgname,
        tax_no: line.tax_no,
        addr: line.addr,
        tel: line.tel,
        bank_name: line.bank_name,
        account_no: line.account_no,
        remark: line.remark,
        payee: line.payee,
        reviewer: line.reviewer,
        drawer: line.drawer,
        details: details,
        invoice_no: line.invoice_no,
        invoice_code: line.invoice_code,
        invoice_date: line.read_only === 'true' ? line.invoice_date : '',
        read_only: line.read_only === 'true',
        invoice_type_name: invoice_type_name,
        oriDetails: fromJS(details).toJS(),
        timestamp: new Date().getTime() + '',
        loading: false
      })
      this.getRequired(line.invoice_type)
      UtilsDM.querySuccess(result)
    } else {
@@ -306,6 +417,25 @@
    }
  }
  clearData = () => {
    this.setState({
      ID: Utils.getguid(),
      from_to_name: '',
      from_to_tax_no: '',
      from_to_addr: '',
      from_to_tel: '',
      from_to_bank_name: '',
      from_to_account_no: '',
      from_to_mob: '',
      from_to_email: '',
      from_to_code: '',
      business_type: '',
      details: [],
      oriDetails: [],
      timestamp: new Date().getTime() + '',
    })
  }
  changeType = (val) => {
    sessionStorage.setItem('pre_invoice_type', val)
    this.setState({invoice_type: val})
@@ -313,7 +443,13 @@
  }
  getRequired = (invoice_type) => {
    if (!invoice_type) return
    if (!invoice_type) {
      this.setState({
        reqfields: [],
        requireds: []
      })
      return
    }
    let reqfields = []
    let requireds = []
@@ -357,30 +493,45 @@
  }
  saveBill = () => {
    const { config, saveType } = this.state
    const { config, BID, saveType } = this.state
    if (saveType) return
    setTimeout(() => {
      this.getBillMsg().then(() => {
        let sql = this.getPreSql(config.billSaveBtn)
        let param = {
          func: 'sPC_TableData_InUpDe',
          LText: sql,
          exec_type: window.GLOB.execType || 'y',
          timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
        let param = null
        if (window.backend && window.GLOB.CacheData.has('sql_' + config.uuid + config.billSaveBtn.type)) {
          param = this.getBackPreParam(config.billSaveBtn)
        } else {
          let sql = this.getPreSql(config.billSaveBtn)
          param = {
            func: 'sPC_TableData_InUpDe',
            LText: sql,
            exec_type: window.GLOB.execType || 'y',
            timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
            BID: BID
          }
          param.secretkey = Utils.encrypt('', param.timestamp)
          param.LText = Utils.formatOptions(param.LText, param.exec_type)
        }
        param.secretkey = Utils.encrypt('', param.timestamp)
        param.LText = Utils.formatOptions(param.LText, param.exec_type)
        this.setState({
          saveType: 'bill'
        })
        Api.genericInterface(param).then(res => {
          this.setState({
            saveType: ''
          })
          if (res.status) {
            if (config.billSaveBtn.reTabId) {
              MKEmitter.emit('reloadMenuView', config.billSaveBtn.reTabId)
            }
            if (config.billSaveBtn.syncComId) {
              MKEmitter.emit('reloadData', config.billSaveBtn.syncComId)
            }
            notification.success({
              top: 92,
              message: '保存成功。',
@@ -393,9 +544,6 @@
              duration: 5
            })
          }
          this.setState({
            saveType: ''
          })
        })
      }, (error) => {
        notification.warning({
@@ -403,33 +551,79 @@
          message: error,
          duration: 5
        })
        return
      })
    }, 20)
  }
  outBill = () => {
    const { config, saveType } = this.state
    const { config, BID, saveType } = this.state
    if (window.GLOB.storeFiles) {
      if (!window.GLOB.storeDate || window.GLOB.storeDate < 0) {
        Modal.warning({
          title: `电子档案存储包已过期。`,
          okText: '知道了'
        })
        return
      } else if (window.GLOB.storeDate < 30) {
        notification.warning({
          top: 92,
          message: `电子档案存储包还剩${window.GLOB.storeDate}天。`,
          duration: 5
        })
      }
    }
    if (window.GLOB.systemType === 'production' && !config.billOutBtn.proInterface) {
      notification.warning({
        top: 92,
        message: '尚未设置正式系统接口地址!',
        duration: 5
      })
      return
    }
    if (saveType) return
    setTimeout(() => {
      this.getBillMsg().then(() => {
        let sql = this.getPreSql(config.billOutBtn)
        let param = {
          func: 'sPC_TableData_InUpDe',
          // BID: BID || '',
          LText: sql,
          key_back_type: 'Y',
          exec_type: window.GLOB.execType || 'y',
          timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
        let param = null
        if (window.backend && window.GLOB.CacheData.has('sql_' + config.uuid + config.billOutBtn.type)) {
          param = this.getBackPreParam(config.billOutBtn)
        } else {
          let sql = this.getPreSql(config.billOutBtn)
          param = {
            func: 'sPC_TableData_InUpDe',
            LText: sql,
            script_type: 'Y',
            exec_type: window.GLOB.execType || 'y',
            timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
            BID: BID
          }
          param.secretkey = Utils.encrypt('', param.timestamp)
          param.LText = Utils.formatOptions(param.LText, param.exec_type)
        }
        param.secretkey = Utils.encrypt('', param.timestamp)
        param.LText = Utils.formatOptions(param.LText, param.exec_type)
        console.info(sql)
        this.setState({
          saveType: 'out'
        })
        Api.genericInterface(param).then(res => {
          if (res.status) {
            this.outPutBill(res)
          } else {
            notification.warning({
              top: 92,
              message: res.message,
              duration: 5
            })
            this.setState({
              saveType: ''
            })
          }
        })
      }, (error) => {
        notification.warning({
          top: 92,
@@ -441,10 +635,15 @@
    })
  }
  getPreSql = (btn) => {
    const { book, details, invoice_type, from_to_name, from_to_tax_no, from_to_addr, from_to_tel, from_to_bank_name, from_to_account_no, from_to_mob, from_to_email, from_to_code, orgname, tax_no, addr, tel, bank_name, account_no, remark, reviewer, drawer, payee } = this.state
  goback = () => {
    const { config } = this.state
    MKEmitter.emit('closeTabView', config.$pageId)
  }
    let userName = sessionStorage.getItem('User_Name') || ''
  getPreSql = (btn) => {
    const { config, book, ID, BID, io, details, oriDetails, business_type, invoice_type, from_to_name, from_to_tax_no, from_to_addr, from_to_tel, from_to_bank_name, from_to_account_no, from_to_mob, from_to_email, from_to_code, orgname, tax_no, addr, tel, bank_name, account_no, remark, reviewer, drawer, payee } = this.state
    let userName = sessionStorage.getItem('User_Name') || ''
    let fullName = sessionStorage.getItem('Full_Name') || ''
    let RoleID = sessionStorage.getItem('role_id') || ''
    let departmentcode = sessionStorage.getItem('departmentcode') || ''
@@ -455,8 +654,43 @@
    let city = sessionStorage.getItem('city') || ''
    let district = sessionStorage.getItem('district') || ''
    let address = sessionStorage.getItem('address') || ''
    let options = fromJS(oriDetails).toJS()
    let price = 0
    let tax = 0
    let lines = details.map(line => `Select '${line.productcode}', '${line.productname}', '${line.spec}', '${line.unit}', ${line.bill_count}, ${line.unitprice}, ${line.amount_line}, '${line.tax_classify_code}', '${line.tax_classify_name}', ${line.tax_rate}, ${line.tax_amount}`)
    let lines = []
    details.forEach(line => {
      if (!line.productcode) return
      let _sql = `Select '${line.productcode}', '${line.productname}', '${line.spec}', '${line.unit}', ${line.bill_count}, ${line.unitprice}, ${line.amount_line}, '${line.tax_classify_code}', '${line.tax_classify_name}', ${line.tax_rate}, ${line.tax_amount}, '${line.free_tax_mark || ''}', '${line.vat_special_management || ''}', '${line.invoice_lp || ''}', '${line.tax_item}', '${line.tax_method}', '${line.uuid}'`
      let data_type = 'add'
      price += line.amount_line * 100
      tax += line.tax_amount * 100
      if (options.length) {
        options = options.filter(option => {
          if (option.uuid === line.uuid) {
            data_type = 'upt'
            return false
          }
          return true
        })
      }
      lines.push(_sql + `, '${data_type}'`)
    })
    let _total = (price - tax) / 100
    price = price / 100
    tax = tax / 100
    if (options.length) {
      options.forEach(line => {
        lines.push(`Select '${line.productcode}', '${line.productname}', '${line.spec}', '${line.unit}', ${line.bill_count}, ${line.unitprice}, ${line.amount_line}, '${line.tax_classify_code}', '${line.tax_classify_name}', ${line.tax_rate}, ${line.tax_amount}, '${line.free_tax_mark || ''}', '${line.vat_special_management || ''}', '${line.invoice_lp || ''}', '${line.tax_item}', '${line.tax_method}', '${line.uuid}', 'del'`)
      })
    }
    lines = lines.join(' union all ')
    let _script = ''
@@ -470,32 +704,39 @@
    let sql = `/* 系统字段 */
      Declare @UserName nvarchar(50), @FullName nvarchar(50), @RoleID nvarchar(512), @mk_departmentcode nvarchar(512), @mk_organization nvarchar(512), @mk_user_type nvarchar(20), @mk_nation nvarchar(50), @mk_province nvarchar(50), @mk_city nvarchar(50), @mk_district nvarchar(50), @mk_address nvarchar(100), @ErrorCode nvarchar(50), @retmsg nvarchar(4000), @account_id nvarchar(50), @account_year_id nvarchar(50), @account_code nvarchar(50), @account_year_code nvarchar(50), @bid nvarchar(50), @tbid nvarchar(50)
      Select @UserName='${userName}', @FullName='${fullName}', @RoleID='${RoleID}', @mk_departmentcode='${departmentcode}', @mk_organization='${organization}', @mk_user_type='${mk_user_type}', @mk_nation='${nation}', @mk_province='${province}', @mk_city='${city}', @mk_district='${district}', @mk_address='${address}', @ErrorCode='', @retmsg='', @account_id='${book.account_id || ''}', @account_year_id='${book.account_year_id || ''}', @account_code='${book.account_code || ''}', @account_year_code='${book.account_year_code || ''}', @bid=''
      Select @UserName='${userName}', @FullName='${fullName}', @RoleID='${RoleID}', @mk_departmentcode='${departmentcode}', @mk_organization='${organization}', @mk_user_type='${mk_user_type}', @mk_nation='${nation}', @mk_province='${province}', @mk_city='${city}', @mk_district='${district}', @mk_address='${address}', @ErrorCode='', @retmsg='', @account_id='${book.account_id || ''}', @account_year_id='${book.account_year_id || ''}', @account_code='${book.account_code || ''}', @account_year_code='${book.account_year_code || ''}', @bid='${BID}'
      /* 发票主表字段 */
      Declare @invoice_type Nvarchar(50), @from_to_name Nvarchar(50), @from_to_tax_no Nvarchar(50), @from_to_addr Nvarchar(100), @from_to_tel Nvarchar(50), @from_to_bank_name Nvarchar(50), @from_to_account_no Nvarchar(50), @from_to_mob Nvarchar(50), @from_to_email Nvarchar(50), @from_to_code Nvarchar(50), @orgname Nvarchar(50), @tax_no Nvarchar(50), @addr Nvarchar(100), @tel Nvarchar(50), @bank_name Nvarchar(50), @account_no Nvarchar(50), @remark Nvarchar(512), @payee Nvarchar(50), @reviewer Nvarchar(50), @drawer Nvarchar(50)
      Declare @invoice_type Nvarchar(50), @from_to_name Nvarchar(50), @from_to_tax_no Nvarchar(50), @from_to_addr Nvarchar(100), @from_to_tel Nvarchar(50), @from_to_bank_name Nvarchar(50), @from_to_account_no Nvarchar(50), @from_to_mob Nvarchar(50), @from_to_email Nvarchar(50), @from_to_code Nvarchar(50), @orgname Nvarchar(50), @tax_no Nvarchar(50), @addr Nvarchar(100), @tel Nvarchar(50), @bank_name Nvarchar(50), @account_no Nvarchar(50), @remark Nvarchar(512), @payee Nvarchar(50), @reviewer Nvarchar(50), @drawer Nvarchar(50), @io Nvarchar(50), @orgcode Nvarchar(50), @total_net_amount Decimal(18,2), @total_tax Decimal(18,2), @total_amount Decimal(18,2), @business_type Nvarchar(20)
      Select @invoice_type='${invoice_type}', @from_to_name='${from_to_name}', @from_to_tax_no='${from_to_tax_no}', @from_to_addr='${from_to_addr}', @from_to_tel='${from_to_tel}', @from_to_bank_name='${from_to_bank_name}', @from_to_account_no='${from_to_account_no}', @from_to_mob='${from_to_mob}', @from_to_email='${from_to_email}', @from_to_code='${from_to_code}', @orgname='${orgname}', @tax_no='${tax_no}', @addr='${addr}', @tel='${tel}', @bank_name='${bank_name}', @account_no='${account_no}', @remark='${remark}', @payee='${payee}', @reviewer='${reviewer}', @drawer='${drawer}'
      Select @invoice_type='${invoice_type}', @from_to_name='${from_to_name}', @from_to_tax_no='${from_to_tax_no}', @from_to_addr='${from_to_addr}', @from_to_tel='${from_to_tel}', @from_to_bank_name='${from_to_bank_name}', @from_to_account_no='${from_to_account_no}', @from_to_mob='${from_to_mob}', @from_to_email='${from_to_email}', @from_to_code='${from_to_code}', @orgname='${orgname}', @tax_no='${tax_no}', @addr='${addr}', @tel='${tel}', @bank_name='${bank_name}', @account_no='${account_no}', @remark='${remark}', @payee='${payee}', @reviewer='${reviewer}', @drawer='${drawer}', @io='${io}', @orgcode='${book.orgcode || ''}', @total_net_amount=${_total}, @total_tax=${tax}, @total_amount=${price}, @business_type='${business_type || config.wrap.business_type || ''}'
      /* 发票明细临时表 */
      Declare @details_list table (productcode Nvarchar(50), productname Nvarchar(50), spec Nvarchar(50), unit Nvarchar(50), bill_count Decimal(18,10), unitprice Decimal(18,10), amount_line Decimal(18,2), tax_classify_code Nvarchar(50), tax_classify_name Nvarchar(50), tax_rate Decimal(18,2), tax_amount Decimal(18,2))
      Declare @details_list table (productcode Nvarchar(50), productname Nvarchar(50), spec Nvarchar(50), unit Nvarchar(50), bill_count Decimal(18,10), unitprice Decimal(18,10), amount_line Decimal(18,2), tax_classify_code Nvarchar(50), tax_classify_name Nvarchar(50), tax_rate Decimal(18,2), tax_amount Decimal(18,2), free_tax_mark Nvarchar(50), vat_special_management Nvarchar(50), invoice_lp Nvarchar(50), tax_item Nvarchar(50), tax_method Nvarchar(50), jskey Nvarchar(50), data_type Nvarchar(50))
      Insert into @details_list (productcode, productname, spec, unit, bill_count, unitprice, amount_line, tax_classify_code, tax_classify_name, tax_rate, tax_amount)
      Insert into @details_list (productcode, productname, spec, unit, bill_count, unitprice, amount_line, tax_classify_code, tax_classify_name, tax_rate, tax_amount, free_tax_mark, vat_special_management, invoice_lp, tax_item, tax_method, jskey, data_type)
      ${lines}
      /* 自定义脚本 */
      ${_script}
      `
      aaa: select @ErrorCode as ErrorCode,@retmsg as retmsg`
    if (btn.type === 'billout') {
      sql += `aaa: if @ErrorCode!=''
      insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select @time_id@,@ErrorCode, @retmsg, @UserID@`
    } else {
      sql += `aaa: select @ErrorCode as ErrorCode,@retmsg as retmsg`
    }
    sql = sql.replace(/@ID@/ig, `''`)
    sql = sql.replace(/@BID@/ig, `''`)
    sql = sql.replace(/@ID@/ig, `'${ID}'`)
    sql = sql.replace(/@BID@/ig, `'${BID}'`)
    sql = sql.replace(/@LoginUID@/ig, `'${sessionStorage.getItem('LoginUID') || ''}'`)
    sql = sql.replace(/@SessionUid@/ig, `'${localStorage.getItem('SessionUid') || ''}'`)
    sql = sql.replace(/@UserID@/ig, `'${sessionStorage.getItem('UserID') || ''}'`)
    sql = sql.replace(/@Appkey@/ig, `'${window.GLOB.appkey || ''}'`)
    sql = sql.replace(/@lang@/ig, `'${sessionStorage.getItem('lang')}'`)
    sql = sql.replace(/@typename@/ig, `'admin'`)
    if (window.GLOB.externalDatabase !== null) {
@@ -509,10 +750,203 @@
    }
    if (window.GLOB.debugger === true) {
      console.info(sql.replace(/\n\s{6}/ig, '\n'))
      window.mkInfo(sql.replace(/\n\s{6}/ig, '\n'))
    }
    return sql
  }
  getBackPreParam = (btn) => {
    const { config, book, ID, BID, io, details, oriDetails, business_type, invoice_type, from_to_name, from_to_tax_no, from_to_addr, from_to_tel, from_to_bank_name, from_to_account_no, from_to_mob, from_to_email, from_to_code, orgname, tax_no, addr, tel, bank_name, account_no, remark, reviewer, drawer, payee } = this.state
    let ex = window.GLOB.CacheData.get('sql_' + btn.uuid + btn.type)
    let exps = []
    let values = {
      time_id: Utils.getguid(),
      roleid: sessionStorage.getItem('role_id') || '',
      mk_departmentcode: sessionStorage.getItem('departmentcode') || '',
      mk_organization: sessionStorage.getItem('organization') || '',
      mk_user_type: sessionStorage.getItem('mk_user_type') || '',
      mk_nation: sessionStorage.getItem('nation') || '',
      mk_province: sessionStorage.getItem('province') || '',
      mk_city: sessionStorage.getItem('city') || '',
      mk_district: sessionStorage.getItem('district') || '',
      mk_address: sessionStorage.getItem('address') || '',
      id: ID || '',
      bid: BID || '',
      datam: sessionStorage.getItem('dataM') === 'true' ? 'Y' : '',
      datam_begin: sessionStorage.getItem('dataM') === 'true' ? 'Y' : '',
      datam_end: sessionStorage.getItem('dataM') === 'true' ? 'Y' : '',
    }
    if (window.GLOB.externalDatabase !== null) {
      values.db = window.GLOB.externalDatabase
    }
    let options = fromJS(oriDetails).toJS()
    let price = 0
    let tax = 0
    let lines = []
    details.forEach(line => {
      if (!line.productcode) return
      let vals = [line.productcode, line.productname, line.spec, line.unit, line.bill_count, line.unitprice, line.amount_line, line.tax_classify_code, line.tax_classify_name, line.tax_rate, line.tax_amount, line.free_tax_mark || '', line.vat_special_management || '', line.invoice_lp || '', line.tax_item, line.tax_method, line.uuid]
      let data_type = 'add'
      price += line.amount_line * 100
      tax += line.tax_amount * 100
      if (options.length) {
        options = options.filter(option => {
          if (option.uuid === line.uuid) {
            data_type = 'upt'
            return false
          }
          return true
        })
      }
      vals.push(data_type)
      lines.push(vals)
    })
    let _total = (price - tax) / 100
    price = price / 100
    tax = tax / 100
    if (options.length) {
      options.forEach(line => {
        let vals = [line.productcode, line.productname, line.spec, line.unit, line.bill_count, line.unitprice, line.amount_line, line.tax_classify_code, line.tax_classify_name, line.tax_rate, line.tax_amount, line.free_tax_mark || '', line.vat_special_management || '', line.invoice_lp || '', line.tax_item, line.tax_method, line.uuid, 'del']
        vals = vals.map(val => typeof(val) === 'number' ? val + '' : val)
        lines.push(vals)
      })
    }
    ex.reps.forEach(n => {
      let key = n.toLowerCase()
      if (values.hasOwnProperty(key)) {
        exps.push({
          key: n,
          value: values[key]
        })
      }
    })
    exps.push({
      key: 'account_id',
      value: book.account_id || ''
    }, {
      key: 'account_year_id',
      value: book.account_year_id || ''
    }, {
      key: 'account_code',
      value: book.account_code || ''
    }, {
      key: 'account_year_code',
      value: book.account_year_code || ''
    }, {
      key: 'invoice_type',
      value: invoice_type
    }, {
      key: 'from_to_name',
      value: from_to_name
    }, {
      key: 'from_to_tax_no',
      value: from_to_tax_no
    }, {
      key: 'from_to_addr',
      value: from_to_addr
    }, {
      key: 'from_to_tel',
      value: from_to_tel
    }, {
      key: 'from_to_bank_name',
      value: from_to_bank_name
    }, {
      key: 'from_to_account_no',
      value: from_to_account_no
    }, {
      key: 'from_to_mob',
      value: from_to_mob
    }, {
      key: 'from_to_email',
      value: from_to_email
    }, {
      key: 'from_to_code',
      value: from_to_code
    }, {
      key: 'orgname',
      value: orgname
    }, {
      key: 'tax_no',
      value: tax_no
    }, {
      key: 'addr',
      value: addr
    }, {
      key: 'tel',
      value: tel
    }, {
      key: 'bank_name',
      value: bank_name
    }, {
      key: 'account_no',
      value: account_no
    }, {
      key: 'remark',
      value: remark
    }, {
      key: 'payee',
      value: payee
    }, {
      key: 'reviewer',
      value: reviewer
    }, {
      key: 'drawer',
      value: drawer
    }, {
      key: 'io',
      value: io
    }, {
      key: 'orgcode',
      value: book.orgcode || ''
    }, {
      key: 'total_net_amount',
      value: _total
    }, {
      key: 'total_tax',
      value: tax
    }, {
      key: 'total_amount',
      value: price
    }, {
      key: 'business_type',
      value: business_type || config.wrap.business_type || ''
    })
    exps.push({
      key: 'mk_excel_data',
      value: lines
    })
    let md5_id = ''
    if (window.GLOB.probation) {
      md5_id = md5(ex.id + JSON.stringify(exps) + Math.floor(new Date().getTime() / 600000))
      md5_id = moment().format('YYYYMMDDHHmmss') + md5_id.slice(-18)
    }
    return {
      $backend: true,
      $type: 's_TableData_InUpDe',
      data: [{
        id: ex.id,
        menuname: btn.logLabel || '',
        exps: exps,
        md5_id: md5_id
      }]
    }
  }
  getBillMsg = () => {
@@ -544,7 +978,7 @@
      }
      if (!error) {
        if (details.length === 0) {
        if (details.length === 0 || details.filter(line => !!line.productcode).length === 0) {
          error = '请添加明细!'
        } else {
          details.forEach((line, index) => {
@@ -555,8 +989,6 @@
              } else if (!line.unitprice) {
                error = '明细第' + (index + 1) + '行,请输入单价!'
              }
            } else {
              error = '明细第' + (index + 1) + '行,请选择货物或应税劳务、服务名称!'
            }
          })
        }
@@ -568,6 +1000,422 @@
        resolve()
      }
    })
  }
  outPutBill = (res) => {
    const { config } = this.state
    if (!res.data_invoice || !res.sellerName || !res.taxNo) {
      notification.warning({
        top: 92,
        message: '缺少开票参数!',
        duration: 5
      })
      this.setState({
        saveType: ''
      })
    }
    let param = {
      data: res.data_invoice,
      sellerName: res.sellerName,
      taxNo: res.taxNo
    }
    let trans = {
      e_general: '02',
      e_special: '01'
    }
    param.data.invoiceTypeCode = trans[param.data.invoiceTypeCode] || ''
    if (window.GLOB.storeFiles) {
      param.store = true
    }
    let url = ''
    if (window.GLOB.systemType === 'production') {
      url = config.billOutBtn.proInterface
    } else {
      url = config.billOutBtn.interface
    }
    if (!/^http/.test(url)) {
      url = window.location.origin + url
    }
    let _params = {
      url: url,
      method: 'post',
      headers: { 'Content-Type': 'application/json' },
      data: param
    }
    Api.directRequest(_params).then(result => {
      result.mk_api_key = res.mk_api_key || ''
      this.callBackBill(result)
    })
  }
  callBackBill = (result) => {
    const { config, BID, ID } = this.state
    let param = null
    if (window.backend && window.GLOB.CacheData.has('sql_' + config.uuid + 'billback')) {
      param = this.getCallBackendParam(config.billOutBtn, result)
    } else {
      let btn = config.billOutBtn
      let lines = []
      let pre = '@'
      let getDefaultSql = (obj, tb, bid, level) => {
        let keys = []
        let vals = []
        let subObjs = []
        let id = Utils.getuuid()
        let tbName = pre + tb
        delete obj.$$key
        Object.keys(obj).forEach(key => {
          let val = obj[key]
          if (val === null || val === undefined) return
          if (typeof(val) === 'object') {
            if (Array.isArray(val)) {
              val.forEach(item => {
                if (typeof(item) !== 'object' || Array.isArray(item)) return
                if (Object.keys(item).length === 0) return
                Object.keys(item).forEach(k => {
                  if (item[k] === null) {
                    item[k] = ''
                  }
                })
                item.$$key = tb + '_' + key
                subObjs.push(item)
              })
            } else if (Object.keys(val).length > 0) {
              val.$$key = tb + '_' + key
              subObjs.push(val)
            }
          } else {
            if (typeof(val) === 'string') {
              val = val.replace(/'/ig, '"')
            }
            keys.push('[' + key + ']')
            vals.push(`'${val}'`)
          }
        })
        keys = keys.join(',')
        vals = vals.join(',')
        lines.push({
          table: md5(tb + keys),
          insert: `Insert into ${tbName} (${keys ? keys + ',' : ''}[mk_level],[mk_id],[mk_bid])`,
          select: `Select ${keys ? vals + ',' : ''}'${level}','${id}','${bid}'`
        })
        subObjs.forEach(item => {
          getDefaultSql(item, item.$$key, id, level + 1)
        })
      }
      getDefaultSql(result, btn.cbTable, '', 1)
      let lineMap = new Map()
      lines.forEach(line => {
        if (lineMap.has(line.table)) {
          let _line = lineMap.get(line.table)
          _line.selects.push(line.select)
          lineMap.set(line.table, _line)
        } else {
          lineMap.set(line.table, {
            table: line.table,
            insert: line.insert,
            selects: [line.select]
          })
        }
      })
      param = {
        func: 'sPC_TableData_InUpDe',
        BID: BID,
        menuname: config.name + '(回调)'
      }
      let callbacksql = this.getBackSql()
      let _prevCustomScript = `${callbacksql}
      `
      let _backCustomScript = ''
      btn.cbScripts.forEach(script => {
        if (script.status === 'false') return
        if (script.position === 'front') {
          _prevCustomScript += `
        /* 自定义脚本 */
        ${script.sql}
        `
        } else {
          _backCustomScript += `
        /* 自定义脚本 */
        ${script.sql}
        `
        }
      })
      _backCustomScript += `
        aaa: select @ErrorCode as ErrorCode,@retmsg as retmsg`
      let sql = [...lineMap.values()].map(item => (`
        ${item.insert}
        ${item.selects.join(` union all
        `)}
      `))
      sql = sql.join('')
      sql = _prevCustomScript + sql
      sql = sql + _backCustomScript
      sql = sql.replace(/@ID@/ig, `'${ID || ''}'`)
      sql = sql.replace(/@BID@/ig, `'${BID || ''}'`)
      sql = sql.replace(/@LoginUID@/ig, `'${sessionStorage.getItem('LoginUID') || ''}'`)
      sql = sql.replace(/@SessionUid@/ig, `'${localStorage.getItem('SessionUid') || ''}'`)
      sql = sql.replace(/@UserID@/ig, `'${sessionStorage.getItem('UserID') || ''}'`)
      sql = sql.replace(/@Appkey@/ig, `'${window.GLOB.appkey || ''}'`)
      sql = sql.replace(/@lang@/ig, `'${sessionStorage.getItem('lang')}'`)
      sql = sql.replace(/@typename@/ig, `'admin'`)
      if (sessionStorage.getItem('dataM') === 'true') { // 数据权限
        sql = sql.replace(/\$@/ig, '/*').replace(/@\$/ig, '*/').replace(/@datam@/ig, `'Y'`)
      } else {
        sql = sql.replace(/@\$|\$@/ig, '').replace(/@datam@/ig, `''`)
      }
      if (window.GLOB.debugger === true) {
        window.mkInfo('%c' + config.name + '(回调)', 'color: blue')
        window.mkInfo(sql.replace(/\n\s{8}/ig, '\n'))
      }
      param.LText = sql
      param.exec_type = window.GLOB.execType || 'y' // 后台解码
      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
      param.secretkey = Utils.encrypt('', param.timestamp)
      param.LText = Utils.formatOptions(param.LText, param.exec_type)
      if (window.GLOB.probation) {
        param.s_debug_type = 'Y'
      }
    }
    Api.genericInterface(param).then(res => {
      this.setState({
        saveType: ''
      })
      if (res.status) {
        if (config.billOutBtn.reTabId) {
          MKEmitter.emit('reloadMenuView', config.billOutBtn.reTabId)
        }
        if (config.billOutBtn.syncComId) {
          MKEmitter.emit('reloadData', config.billOutBtn.syncComId)
        }
        this.clearData()
        notification.success({
          top: 92,
          message: '开票成功。',
          duration: 5
        })
      } else {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 5
        })
      }
    })
  }
  getCallBackendParam = (btn, result) => {
    const { book, BID, ID } = this.state
    let lines = []
    let tables = []
    btn.verify.cbScripts.forEach(script => {
      if (script.status === 'false') return
      if (/\s#[a-z0-9_]+(\s|\()/ig.test(script.sql)) {
        tables.push(...script.sql.match(/\s#[a-z0-9_]+(\s|\()/ig))
      }
    })
    tables = tables.map(tb => tb.replace(/\s|\(/g, ''))
    if (result.$ErrCode) {
      delete result.$ErrCode
      delete result.$ErrMesg
    }
    let getDefaultSql = (obj, tb, bid, level) => {
      let vals = {}
      let subObjs = []
      let id = Utils.getuuid()
      delete obj.$$key
      Object.keys(obj).forEach(key => {
        let val = obj[key]
        if (val === null || val === undefined) return
        if (typeof(val) === 'object') {
          if (Array.isArray(val)) {
            val.forEach(item => {
              if (typeof(item) !== 'object' || Array.isArray(item)) return
              if (Object.keys(item).length === 0) return
              Object.keys(item).forEach(k => {
                if (item[k] === null) {
                  item[k] = ''
                }
              })
              item.$$key = tb + '_' + key
              subObjs.push(item)
            })
          } else if (Object.keys(val).length > 0) {
            val.$$key = tb + '_' + key
            subObjs.push(val)
          }
        } else {
          if (typeof(val) === 'string') {
            val = val.replace(/'/ig, '"')
          } else {
            val = val + ''
          }
          vals[key] = val
        }
      })
      vals.mk_level = level
      vals.mk_id = id
      vals.mk_bid = bid
      let isnew = true
      lines.forEach(line => {
        if (line.tb === tb) {
          line.values.push(vals)
          isnew = false
        }
      })
      if (isnew) {
        lines.push({
          tb: tb,
          type: tables.includes('#' + tb) ? '01' : '02',
          values: [vals]
        })
      }
      subObjs.forEach(item => {
        getDefaultSql(item, item.$$key, id, level + 1)
      })
    }
    getDefaultSql(result, btn.cbTable, '', 1)
    let ex = window.GLOB.CacheData.get('sql_' + btn.uuid + 'billback')
    let exps = []
    let values = {
      time_id: Utils.getguid(),
      roleid: sessionStorage.getItem('role_id') || '',
      mk_departmentcode: sessionStorage.getItem('departmentcode') || '',
      mk_organization: sessionStorage.getItem('organization') || '',
      mk_user_type: sessionStorage.getItem('mk_user_type') || '',
      mk_nation: sessionStorage.getItem('nation') || '',
      mk_province: sessionStorage.getItem('province') || '',
      mk_city: sessionStorage.getItem('city') || '',
      mk_district: sessionStorage.getItem('district') || '',
      mk_address: sessionStorage.getItem('address') || '',
      id: ID || '',
      bid: BID || '',
      datam: sessionStorage.getItem('dataM') === 'true' ? 'Y' : '',
      datam_begin: sessionStorage.getItem('dataM') === 'true' ? 'Y' : '',
      datam_end: sessionStorage.getItem('dataM') === 'true' ? 'Y' : '',
    }
    if (window.GLOB.externalDatabase !== null) {
      values.db = window.GLOB.externalDatabase
    }
    ex.reps.forEach(n => {
      let key = n.toLowerCase()
      if (values.hasOwnProperty(key)) {
        exps.push({
          key: n,
          value: values[key]
        })
      }
    })
    exps.push({
      key: 'account_id',
      value: book.account_id || ''
    }, {
      key: 'account_year_id',
      value: book.account_year_id || ''
    }, {
      key: 'account_code',
      value: book.account_code || ''
    }, {
      key: 'account_year_code',
      value: book.account_year_code || ''
    })
    exps.push({
      key: 'mk_outer_params',  // 回调脚本的数据替换
      value: lines
    })
    let md5_id = ''
    if (window.GLOB.probation) {
      md5_id = md5('back_' + btn.uuid + JSON.stringify(exps) + Math.floor(new Date().getTime() / 600000))
      md5_id = moment().format('YYYYMMDDHHmmss') + md5_id.slice(-18)
    }
    return {
      $backend: true,
      $type: 's_TableData_InUpDe',
      data: [{
        id: ex.id,
        menuname: btn.logLabel + '(回调)',
        exps: exps,
        md5_id: md5_id
      }]
    }
  }
  getBackSql = () => {
    const { book, BID } = this.state
    let userName = sessionStorage.getItem('User_Name') || ''
    let fullName = sessionStorage.getItem('Full_Name') || ''
    let RoleID = sessionStorage.getItem('role_id') || ''
    let departmentcode = sessionStorage.getItem('departmentcode') || ''
    let organization = sessionStorage.getItem('organization') || ''
    let mk_user_type = sessionStorage.getItem('mk_user_type') || ''
    let nation = sessionStorage.getItem('nation') || ''
    let province = sessionStorage.getItem('province') || ''
    let city = sessionStorage.getItem('city') || ''
    let district = sessionStorage.getItem('district') || ''
    let address = sessionStorage.getItem('address') || ''
    let sql = `/* 系统字段 */
      Declare @UserName nvarchar(50), @FullName nvarchar(50), @RoleID nvarchar(512), @mk_departmentcode nvarchar(512), @mk_organization nvarchar(512), @mk_user_type nvarchar(20), @mk_nation nvarchar(50), @mk_province nvarchar(50), @mk_city nvarchar(50), @mk_district nvarchar(50), @mk_address nvarchar(100), @ErrorCode nvarchar(50), @retmsg nvarchar(4000), @account_id nvarchar(50), @account_year_id nvarchar(50), @account_code nvarchar(50), @account_year_code nvarchar(50), @bid nvarchar(50), @tbid nvarchar(50)
      Select @UserName='${userName}', @FullName='${fullName}', @RoleID='${RoleID}', @mk_departmentcode='${departmentcode}', @mk_organization='${organization}', @mk_user_type='${mk_user_type}', @mk_nation='${nation}', @mk_province='${province}', @mk_city='${city}', @mk_district='${district}', @mk_address='${address}', @ErrorCode='', @retmsg='', @account_id='${book.account_id || ''}', @account_year_id='${book.account_year_id || ''}', @account_code='${book.account_code || ''}', @account_year_code='${book.account_year_code || ''}', @bid='${BID || ''}'
      `
    return sql
  }
  changeBuyer = (item) => {
@@ -585,16 +1433,138 @@
    })
  }
  render() {
    const { config, book, loading, invTypes, reqfields, saveType, date, invoice_type, from_to_name, from_to_tax_no, from_to_addr, from_to_tel, from_to_bank_name, from_to_account_no, from_to_mob, from_to_email, orgname, tax_no, addr, tel, bank_name, account_no, remark, reviewer, drawer, payee, details, visible, tax_type } = this.state
  addInvice = () => {
    const { saveType } = this.state
    if (!book || (config.wrap.datatype === 'dynamic' && !tax_no)) {
    if (saveType) {
      notification.warning({
        top: 92,
        message: saveType === 'bill' ? '单据保存中,请稍后。' : '开票中,请稍后。',
        duration: 3
      })
      return
    }
    this.clearData()
    notification.success({
      top: 92,
      message: '单据已更新。',
      duration: 3
    })
  }
  // jumpSys = () => {
  //   window.open(`${window.location.origin}/kgcs/thirdPlatFormLogin?userName=admin&taxCode=91120222MA07GMNW97&taxName=天津畅享数字科技有限公司`)
  // }
  render() {
    const { config, book, loading, invTypes, reqfields, saveType, date, timestamp, invoice_type, from_to_name, from_to_tax_no, from_to_addr, from_to_tel, from_to_bank_name, from_to_account_no, from_to_mob, from_to_email, orgname, tax_no, addr, tel, bank_name, account_no, remark, reviewer, drawer, payee, details, visible, tax_type, invoice_no, invoice_code, invoice_date, read_only, invoice_type_name } = this.state
    if (!book || (config.wrap.datatype === 'dynamic' && !timestamp)) {
      return <div className="menu-invoice-wrap" style={config.style}>
        <div className="loading-mask">
          <div className="ant-spin-blur"></div>
          <Spin />
        </div>
      </div>
    }
    if (read_only) {
      return (
        <div className="menu-invoice-wrap read_only" style={config.style}>
          {loading ?
            <div className="loading-mask">
              <div className="ant-spin-blur"></div>
              <Spin />
            </div> : null
          }
          <div className="inv-action">
            {config.wrap.backBtn === 'show' ? <Button className="mk-back" onClick={this.goback}><LeftOutlined />返回</Button> : null}
          </div>
          <div className="inv-header">
            <div className="inv-type">{invoice_type_name}</div>
            <div className="inv-msg">
              {invoice_no ? <div>发票号码:{invoice_no}</div> : null}
              {invoice_code ? <div>发票代码:{invoice_code}</div> : null}
              {invoice_date ? <div>开票日期:{invoice_date}</div> : null}
            </div>
          </div>
          <div className="inv-body">
            <div className="inv-main-content">
              <div className="inv-buyer">
                <div className="inv-label">购买方</div>
                <div className="inv-content">
                  <Form.Item className="mk-name" label={<>名<span></span>称</>}>
                    {from_to_name}
                  </Form.Item>
                  <Form.Item label="纳税人识别号">
                    {from_to_tax_no}
                  </Form.Item>
                  <Form.Item label={<>地<span></span>址<span></span>、<span></span>电<span></span>话</>}>
                    {from_to_addr + ' ' + from_to_tel}
                  </Form.Item>
                  <Form.Item label="开户行及账号">
                    {from_to_bank_name + ' ' + from_to_account_no}
                  </Form.Item>
                </div>
              </div>
              <div className="inv-notice">
                <div className="inv-label">通知到</div>
                <div className="inv-content">
                  <Form.Item label={<>手<span></span>机<span></span>号</>}>
                    {from_to_mob}
                  </Form.Item>
                  <Form.Item label={<>邮<span></span>箱</>}>
                    {from_to_email}
                  </Form.Item>
                </div>
              </div>
            </div>
            <div className="inv-details">
              <InvoiceTable data={details} timestamp={timestamp} read_only={true} config={config.detail} tax_type={tax_type} onChange={(details) => this.setState({details})}/>
            </div>
            <div className="inv-main-content">
              <div className="inv-buyer">
                <div className="inv-label">销售方</div>
                <div className="inv-content">
                  <Form.Item label={<>名<span></span>称</>}>
                    {orgname}
                  </Form.Item>
                  <Form.Item label="纳税人识别号">
                    {tax_no}
                  </Form.Item>
                  <Form.Item label={<>地<span></span>址<span></span>、<span></span>电<span></span>话</>}>
                    {addr + ' ' + tel}
                  </Form.Item>
                  <Form.Item label="开户行及账号">
                    {bank_name + ' ' + account_no}
                  </Form.Item>
                </div>
              </div>
              <div className="inv-notice">
                <div className="inv-label">备注</div>
                <div className="inv-content" style={{paddingTop: '30px'}}>
                  <Form.Item label="">
                    {remark}
                  </Form.Item>
                </div>
              </div>
            </div>
          </div>
          <div className="inv-tail">
            <Form.Item label="收款人">
              {payee}
            </Form.Item>
            <Form.Item label="复核人">
              {reviewer}
            </Form.Item>
            <Form.Item label="开票人">
              {drawer}
            </Form.Item>
          </div>
        </div>
      )
    }
    return (
@@ -606,11 +1576,14 @@
          </div> : null
        }
        <div className="inv-action">
          {config.wrap.backBtn === 'show' ? <Button className="mk-back" onClick={this.goback}><LeftOutlined />返回</Button> : null}
          {/* <Button className="mk-addinv" onClick={this.jumpSys}>跳转</Button> */}
          <Button className="mk-addinv" onClick={this.addInvice}>新增发票</Button>
          <Button className="mk-bill" loading={saveType === 'bill'} onClick={this.saveBill}>保存单据</Button>
          <Button className="mk-submit" loading={saveType === 'out'} onClick={this.outBill}>提交开票</Button>
        </div>
        <div className="inv-header">
          {invoice_type ? <Select defaultValue={invoice_type} onChange={this.changeType} dropdownClassName="inv-type-select">
          {invoice_type ? <Select value={invoice_type} onChange={this.changeType} dropdownClassName="inv-type-select">
            {invTypes.map(item => (
              <Select.Option key={item.value} value={item.value}>{item.label}</Select.Option>
            ))}
@@ -626,7 +1599,7 @@
            <div className="inv-buyer">
              <div className="inv-label">购买方</div>
              <div className="inv-content">
                <Form.Item required={reqfields.includes('from_to_name')} label={<>名<span></span>称</>} extra={<EllipsisOutlined onClick={() => this.setState({visible: true})}/>}>
                <Form.Item className="mk-name" required={reqfields.includes('from_to_name')} label={<>名<span></span>称</>} extra={<EllipsisOutlined onClick={() => this.setState({visible: true})}/>}>
                  <Input placeholder="请输入购买方名称" allowClear value={from_to_name} autoComplete="off" onChange={(e) => this.setState({from_to_name: e.target.value})}/>
                </Form.Item>
                <Form.Item required={reqfields.includes('from_to_tax_no')} label="纳税人识别号">
@@ -655,7 +1628,7 @@
            </div>
          </div>
          <div className="inv-details">
            <InvoiceTable data={details} config={config.detail} tax_type={tax_type} onChange={(details) => this.setState({details})}/>
            <InvoiceTable data={details} timestamp={timestamp} read_only={false} config={config.detail} tax_type={tax_type} onChange={(details) => this.setState({details})}/>
          </div>
          <div className="inv-main-content">
            <div className="inv-buyer">
@@ -701,7 +1674,7 @@
        <Modal
          title="客户信息"
          visible={visible}
          width="70vw"
          width="75vw"
          maskClosable={false}
          onCancel={() => { this.setState({ visible: false }) }}
          footer={null}