king
2023-02-14 3620d67cfd2f2af19ef4d656734badd4445c90b8
2023-02-14
12个文件已修改
4个文件已添加
1081 ■■■■■ 已修改文件
src/menu/components/module/voucher/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/module/voucher/index.scss 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/module/voucher/options.jsx 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/actioncomponent/actionform/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/actioncomponent/dragaction/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/module/voucher/index.jsx 445 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/module/voucher/index.scss 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/module/voucher/loadFromTemp/index.jsx 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/module/voucher/loadFromTemp/index.scss 148 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/module/voucher/resetAttach/addAttach/index.jsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/module/voucher/resetAttach/documents/index.jsx 91 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/module/voucher/resetAttach/index.jsx 110 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/module/voucher/resetAttach/index.scss 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/module/voucher/saveAsTemp/index.jsx 122 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/module/voucher/saveAsTemp/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/mutilform/index.jsx 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/module/voucher/index.jsx
@@ -39,7 +39,7 @@
        name: '凭证',
        subtype: card.subtype,
        // setting: { interType: 'system' },
        wrap: { name: '凭证', title: '', width: card.width || 12, type: 'createVoucher' },
        wrap: { name: '凭证', title: '', width: card.width || 12, type: 'createVoucher', space: 30 },
        style: { marginLeft: '8px', marginRight: '8px', marginTop: '8px', marginBottom: '8px', paddingBottom: '20px' },
        headerStyle: {},
        columns: [],
@@ -133,7 +133,7 @@
            <Button className="print-background header-btn">打印</Button>
            <Button className="out-background header-btn">关闭</Button>
          </div> : null}
          <div className="voucher-body">
          <div className="voucher-body" style={{padding: `0px ${card.wrap.space || 0}px`}}>
            {card.wrap.type === 'createVoucher' || card.wrap.type === 'checkVoucher' ? <div className="pre-wrap">
              <div className="voucher-code">
                <div>记<DownOutlined/></div>
src/menu/components/module/voucher/index.scss
@@ -7,6 +7,7 @@
  background-size: cover;
  min-height: 150px;
  overflow-y: auto;
  overflow-x: hidden;
  .anticon-tool {
    position: absolute;
@@ -30,7 +31,6 @@
    }
  }
  .voucher-body {
    padding: 0 30px;
    .voucher-code {
      display: inline-block;
      width: 160px;
src/menu/components/module/voucher/options.jsx
@@ -126,6 +126,14 @@
        {value: 10, label: '已审核'},
      ]
    },
    {
      type: 'number',
      field: 'space',
      label: '留白',
      initval: wrap.space || 0,
      tooltip: '表格主体部分两端的空白距离,表格在编辑时两端会有添加和删除图标。',
      required: false
    },
  ]
  return wrapForm
src/menu/components/share/actioncomponent/actionform/index.jsx
@@ -570,8 +570,8 @@
        _fieldval.label = '导出Excel'
        _fieldval.class = 'dgreen'
        _fieldval.execSuccess = 'never'
        _fieldval.Ot = 'notRequired'
        this.record.Ot = 'notRequired'
        _fieldval.Ot = 'requiredOnce'
        this.record.Ot = 'requiredOnce'
        this.record.label = '导出Excel'
        this.record.class = 'dgreen'
        this.record.execSuccess = 'never'
src/menu/components/share/actioncomponent/dragaction/index.jsx
@@ -128,6 +128,7 @@
          newcard.label = item.text
          newcard.execSuccess = 'never'
          newcard.class = 'dgreen'
          newcard.Ot = 'requiredOnce'
        }
        if (item.overIndex) {
src/tabviews/custom/components/module/voucher/index.jsx
@@ -1,19 +1,20 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Button, Select, Input, Modal, DatePicker, notification, InputNumber } from 'antd'
import { Button, Select, Input, Modal, DatePicker, notification, InputNumber, Dropdown } from 'antd'
import moment from 'moment'
import Api from '@/api'
import Utils from '@/utils/utils.js'
import asyncComponent from '@/utils/asyncComponent'
import MKEmitter from '@/utils/events.js'
import VoucherTable from './voucherTable'
import SaveAsTemp from './saveAsTemp'
import ResetRemark from './resetRemark'
import ResetAttach from './resetAttach'
import LoadFromTemp from './loadFromTemp'
import './index.scss'
const { confirm } = Modal
const VoucherTable = asyncComponent(() => import('./voucherTable'))
const ResetRemark = asyncComponent(() => import('./resetRemark'))
const ResetAttach = asyncComponent(() => import('./resetAttach'))
class VoucherModule extends Component {
  static propTpyes = {
@@ -37,11 +38,16 @@
    remark: '',
    attachments: 0,
    attachlist: [],
    oriAttachs: [],
    tempTypes: [],
    tempTypeClass: '',
    tempTypeName: '',
    title: '',
    orgcode: '',
    orgname: '',
    status: '', // 新建时,empty、change、saved
    saved: false
    saved: false,
    voucherCode: ''
  }
  UNSAFE_componentWillMount () {
@@ -74,11 +80,14 @@
      }
    }
    // config.wrap.type = 'checkVoucher'
    // BID = '20230214130744811P0K95RQ155KG0QIQOFV'
    // config.wrap.type = 'checkTemp'
    // BID = '20230214174458780MFR8IA576ON4VKNOLVH'
    window.GLOB.CacheVoucher.delete(config.uuid)
    let type = config.wrap.type || 'createVoucher'
    // type = 'checkVoucher'
    // BID = '202302081418373862P8Q29OUD19CT1AVMU6'
    if (type === 'createVoucher' || type === 'createTemp') {
      BID = Utils.getguid()
@@ -177,12 +186,14 @@
          charInt: charInt,
          orgcode: res.orgcode,
          orgname: res.orgname,
          tempTypes: res.temp_type || []
        })
      } else {
        this.setState({
          typeOptions: typeOptions,
          orgcode: res.orgcode,
          orgname: res.orgname,
          tempTypes: res.temp_type || []
        })
      }
@@ -263,6 +274,10 @@
      ID: BID
    }
    if (type === 'checkTemp') {
      param.func = 's_get_fcc_voucher_temp'
    }
    Api.genericInterface(param).then(res => {
      if (!res.status) {
        notification.warning({
@@ -304,17 +319,47 @@
        })
      }
      if (type !== 'checkTemp') {
        let files = []
        res.fcc_files && res.fcc_files.forEach(file => {
          file.attachments.forEach(item => {
            item.id = item.attach_id
            item.data_code = file.data_code
            item.data_name = file.data_name
            item.BID = file.id
            files.push(item)
          })
        })
      this.setState({
        data: data,
          attachlist: files,
        vouDate: res.fibvoucherdate ? moment(res.fibvoucherdate, 'YYYY-MM-DD') : null,
        charType: res.voucher_class,
        charName: res.voucher_char,
        charInt: res.voucher_char_int,
        // orgcode: res.orgcode,
        // orgname: res.orgname,
          voucherCode: res.voucher_code || '',
        tbdata: fromJS(data).toJS(),
          oriAttachs: fromJS(files).toJS(),
          attachments: res.attachments_int,
          title: res.voucher_text || '',
          remark: res.remark || '',
        status: 'saved'
      })
      } else {
        this.setState({
          data: data,
          tbdata: fromJS(data).toJS(),
          title: res.voucher_text || '',
          tempTypeClass: res.typechartwo || '',
          tempTypeName: res.typecharthree || '',
          status: 'saved'
        })
      }
    })
  }
@@ -435,7 +480,7 @@
  }
  voucherSave = (list, t) => {
    const { type, data, config, charInt, charType, vouDate, book, remark, charName, attachments, title, orgcode, orgname } = this.state
    const { type, BID, data, config, voucherCode, charInt, charType, vouDate, book, remark, charName, attachments, title, orgcode, orgname, attachlist, oriAttachs } = this.state
    let err = ''
    if (!book) {
@@ -458,8 +503,8 @@
    let param = {
      func: 's_fcc_voucher_addupt',
      BID: book.id,
      ID: Utils.getguid(),
      voucher_code: '',
      ID: BID,
      voucher_code: voucherCode || '',
      voucher_text: title,
      remark: remark,
      account_year_code: book.account_year_code || '',
@@ -565,8 +610,26 @@
      sup_data.push(`'${n.uuid}','${n.sup_voucher_code}','${n.sup_voucher_lp}','${n.voucher_sup_lp || ''}','${n.sup_subject_code}','${n.sup_subject_name}','${n.sup_voucher_text || ''}','${n.sup_direct}',${n.sup_net_amount},'${n.customercode || ''}','${n.customername || ''}','${n.suppliercode || ''}','${n.suppliername || ''}','${n.co_pro_code || ''}','${n.co_pro_name || ''}','${n.workercode || ''}','${n.workername || ''}','${n.project_code || ''}','${n.project_name || ''}','${n.productcode || ''}','${n.productname || ''}','${n.cash_flow_code || ''}','${n.cash_flow_name || ''}','${n.sup_acc_code || ''}','${n.sup_acc_name || ''}','${n.sup_acc_type || ''}','${n.sup_bid}',1`)
    })
    let attachments_data = []
    let ids = []
    attachlist.forEach(item => {
      ids.push(item.id)
      attachments_data.push(`'${item.id}',0`)
    })
    if (oriAttachs.length > 0) {
      oriAttachs.forEach(item => {
        if (!ids.includes(item.id)) {
          attachments_data.push(`'${item.id}',1`)
        }
      })
    }
    param.subject_data = window.btoa(window.encodeURIComponent(subject_data.join(';un')))
    param.sup_data = window.btoa(window.encodeURIComponent(sup_data.join(';un')))
    param.attachments_data = window.btoa(window.encodeURIComponent(attachments_data.join(';un')))
    Api.genericInterface(param).then(res => {
      if (!res.status) {
@@ -589,6 +652,7 @@
          status: 'empty',
          remark: '',
          tbdata: [],
          oriAttachs: fromJS(attachlist).toJS(),
          charInt: res.voucher_char_int + 1,
          BID: Utils.getguid(),
          saved: false
@@ -599,7 +663,244 @@
          status: 'saved',
          charInt: res.voucher_char_int || charInt,
          data: fromJS(list).toJS(),
          oriAttachs: fromJS(attachlist).toJS(),
          saved: true
        })
      }
    })
  }
  triggerTempsave = (name, typeChar, typeName) => {
    const { tbdata } = this.state
    let err = ''
    let list = []
    tbdata.forEach((line, index) => {
      if (err) return
      let _index = index + 1
      if (!line.subject_voucher_text && !line.subject_code) {
        if (_index === 1) {
          err = '第1行不可为空。'
        }
        return
      }
      if (!line.subject_voucher_text) {
        err = `第${_index}行,摘要不可为空。`
      } else if (!line.subject_code) {
        err = `第${_index}行,科目不可为空。`
      } else if (line.sup_accounting && !line.supAccounts) {
        err = `第${_index}行,请选择辅助核算。`
      } else if (line.sup_accounting && line.supAccounts) {
        line.supAccounts.forEach(item => {
          if (item.sup_acc_type === 'supplier') {
            if (!item.suppliercode || !item.suppliername) {
              err = `第${_index}行,请选择辅助核算。`
            }
          } else if (item.sup_acc_type === 'customer') {
            if (!item.customercode || !item.customername) {
              err = `第${_index}行,请选择辅助核算。`
            }
          } else if (item.sup_acc_type === 'department') {
            if (!item.co_pro_code || !item.co_pro_name) {
              err = `第${_index}行,请选择辅助核算。`
            }
          } else if (item.sup_acc_type === 'project') {
            if (!item.projectcode || !item.projectname) {
              err = `第${_index}行,请选择辅助核算。`
            }
          } else if (item.sup_acc_type === 'inventory') {
            if (!item.productcode || !item.productname) {
              err = `第${_index}行,请选择辅助核算。`
            }
          } else if (item.sup_acc_type === 'employee') {
            if (!item.workercode || !item.workername) {
              err = `第${_index}行,请选择辅助核算。`
            }
          } else if (item.sup_acc_type === 'cash_flow') {
            if (!item.cash_flow_code || !item.cash_flow_name) {
              err = `第${_index}行,请选择辅助核算。`
            }
          } else if (!item.sup_acc_type || !item.sup_acc_code || !item.sup_acc_name) {
            err = `第${_index}行,请选择辅助核算。`
          }
        })
      }
      list.push(line)
    })
    if (!err && list.length === 0) {
      err = '第1行不可为空。'
    }
    if (err) {
      notification.warning({
        top: 92,
        message: err,
        duration: 5
      })
      return
    }
    this.voucherTempSave(list, name, typeChar, typeName)
  }
  voucherTempSave = (list, name, typeChar, typeName) => {
    const { type, BID, data, book, title, orgcode, orgname, tempTypeClass, tempTypeName } = this.state
    if (!book) {
      notification.warning({
        top: 92,
        message: '请选择账套!',
        duration: 5
      })
      return
    } else if (type !== 'createVoucher' && !title) {
      notification.warning({
        top: 92,
        message: '请填写模板名称!',
        duration: 5
      })
      return
    } else if (type !== 'createVoucher' && !tempTypeClass) {
      notification.warning({
        top: 92,
        message: '请选择模板类型!',
        duration: 5
      })
      return
    }
    let id = BID
    let _name = title
    let _typeChar = tempTypeClass
    let _typeName = tempTypeName
    if (type === 'createVoucher') {
      id = Utils.getguid()
      _name = name
      _typeChar = typeChar
      _typeName = typeName
    }
    let param = {
      func: 's_fcc_voucher_addupt_temp',
      BID: book.id,
      ID: id,
      voucher_code: '',
      voucher_text: _name,
      remark: '',
      account_year_code: book.account_year_code || '',
      voucher_type: 'fcc_temp',
      voucher_type_text: '凭证模板',
      orgcode: orgcode || '',
      orgname: orgname || '',
      voucher_class: 'temp',
      years: book.years,
      months: moment().format('YYYY-MM'),
      business_type: '',
      voucher_sign: 'temp',
      voucher_char: '',
      voucher_char_int: 0,
      account_code: book.account_code || '',
      fibvoucherdate: moment().format('YYYY-MM-DD'),
      UserName: sessionStorage.getItem('User_Name') || '',
      FullName: sessionStorage.getItem('Full_Name') || '',
      attachments_int: 0,
      typechartwo: _typeChar,
      typecharthree: _typeName,
      sup_data: '',
      subject_data: ''
    }
    let sup_data = []
    let voucherMap = new Map()
    let supMap = new Map()
    if (type !== 'createVoucher') {
      data.forEach(item => {
        voucherMap.set(item.uuid, item)
        if (item.sup_accounting && item.supAccounts) {
          item.supAccounts.forEach(cell => {
            if (!cell.sup_acc_type) return
            let _cell = {...cell}
            _cell.sup_voucher_code = item.subject_voucher_code || ''
            _cell.sup_voucher_lp = item.voucher_lp || ''
            _cell.sup_subject_code = item.subject_code || ''
            _cell.sup_subject_name = item.subject_name || ''
            _cell.sup_bid = item.uuid || ''
            _cell.sup_direct = !item.credit ? 'debit' : 'credit'
            _cell.sup_net_amount = item.debit || item.credit || 0
            supMap.set(item.uuid + cell.sup_acc_type, _cell)
          })
        }
      })
    }
    let subject_data = list.map(item => {
      let count = item.count_type === 'Y'
      let curr = item.foreign_currency_type === 'Y'
      let direct = !item.credit ? 'debit' : 'credit'
      if (voucherMap.has(item.uuid)) {
        voucherMap.delete(item.uuid)
      }
      if (item.sup_accounting && item.supAccounts) {
        item.supAccounts.forEach(n => {
          if (supMap.has(item.uuid + n.sup_acc_type)) {
            supMap.delete(item.uuid + n.sup_acc_type)
          }
          sup_data.push(`'${n.uuid}','${item.subject_voucher_code || ''}','${item.voucher_lp || ''}','${n.voucher_sup_lp || ''}','${item.subject_code}','${item.subject_name}','${n.sup_voucher_text || ''}','${direct}',${item.debit || item.credit || 0},'${n.customercode || ''}','${n.customername || ''}','${n.suppliercode || ''}','${n.suppliername || ''}','${n.co_pro_code || ''}','${n.co_pro_name || ''}','${n.workercode || ''}','${n.workername || ''}','${n.project_code || ''}','${n.project_name || ''}','${n.productcode || ''}','${n.productname || ''}','${n.cash_flow_code || ''}','${n.cash_flow_name || ''}','${n.sup_acc_code || ''}','${n.sup_acc_name || ''}','${n.sup_acc_type || ''}','${item.uuid}',0`)
        })
      }
      return `'${item.uuid}','${item.subject_voucher_code || ''}','${item.voucher_lp || ''}','${item.subject_code}','${item.subject_name}','${item.subject_voucher_text || ''}',${count ? item.fcc_count || 0 : 0},${count ? item.net_unitprice || 0 : 0},'${item.unit}',${item.debit || item.credit || 0},'${direct}','${curr ? item.exratecode : '01010001'}','${curr ? item.exratename : 'CNY'}',${curr ? item.unitratio || 0 : 0},'${item.sup_accounting}',${item.direct ? 1 : -1},${curr ? item.foreign_amount || 0 : 0},0,'${item.local_currency || ''}','${count ? 'Y' : ''}','${curr ? 'Y' : ''}'`
    })
    voucherMap.forEach(item => {
      let count = item.count_type === 'Y'
      let curr = item.foreign_currency_type === 'Y'
      let direct = !item.credit ? 'debit' : 'credit'
      subject_data.push(`'${item.uuid}','${item.subject_voucher_code || ''}','${item.voucher_lp || ''}','${item.subject_code}','${item.subject_name}','${item.subject_voucher_text || ''}',${count ? item.fcc_count || 0 : 0},${count ? item.net_unitprice || 0 : 0},'${item.unit}',${item.debit || item.credit || 0},'${direct}','${curr ? item.exratecode : '01010001'}','${curr ? item.exratename : 'CNY'}',${curr ? item.unitratio || 0 : 0},'${item.sup_accounting}',${item.direct ? 1 : -1},${curr ? item.foreign_amount || 0 : 0},1,'${item.local_currency || ''}','${count ? 'Y' : ''}','${curr ? 'Y' : ''}'`)
    })
    supMap.forEach(n => {
      sup_data.push(`'${n.uuid}','${n.sup_voucher_code}','${n.sup_voucher_lp}','${n.voucher_sup_lp || ''}','${n.sup_subject_code}','${n.sup_subject_name}','${n.sup_voucher_text || ''}','${n.sup_direct}',${n.sup_net_amount},'${n.customercode || ''}','${n.customername || ''}','${n.suppliercode || ''}','${n.suppliername || ''}','${n.co_pro_code || ''}','${n.co_pro_name || ''}','${n.workercode || ''}','${n.workername || ''}','${n.project_code || ''}','${n.project_name || ''}','${n.productcode || ''}','${n.productname || ''}','${n.cash_flow_code || ''}','${n.cash_flow_name || ''}','${n.sup_acc_code || ''}','${n.sup_acc_name || ''}','${n.sup_acc_type || ''}','${n.sup_bid}',1`)
    })
    param.subject_data = window.btoa(window.encodeURIComponent(subject_data.join(';un')))
    param.sup_data = window.btoa(window.encodeURIComponent(sup_data.join(';un')))
    Api.genericInterface(param).then(res => {
      if (!res.status) {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 5
        })
        return
      }
      notification.success({
        top: 92,
        message: '保存成功!',
        duration: 5
      })
      if (type !== 'createVoucher') {
        this.setState({
          status: 'saved',
          data: fromJS(list).toJS(),
        })
      }
    })
@@ -696,16 +997,105 @@
    })
  }
  resetAttachList = (vals) => {
    const { attachlist } = this.state
    let num = this.state.attachments
    if (num) {
      num = num + (vals.length - attachlist.length)
    } else {
      num = vals.length
    }
    if (num < 0) {
      num = 0
    }
    this.setState({attachlist: vals, attachments: num})
  }
  triggermore = () => {
  }
  triggerclose = () => {
    const { config, status } = this.state
    if (status === 'change') {
      confirm({
        content: '内容已变更,确定要关闭吗?',
        onOk() {
          MKEmitter.emit('closeTabView', config.$pageId)
        },
        onCancel() {}
      })
    } else {
      MKEmitter.emit('closeTabView', config.$pageId)
    }
  }
  triggerTempLoad = (id) => {
    const { book } = this.state
    if (!book) return
    let param = {
      func: 's_get_fcc_voucher_temp',
      BID: book.id,
      ID: id
    }
    Api.genericInterface(param).then(res => {
      if (!res.status) {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 5
        })
        return
      }
      let data = []
      if (res.voucher) {
        data = res.voucher.map(line => {
          line.uuid = line.subject_id || ''
          if (line.direction_type === 'credit') {
            line.credit = line.net_amount || 0
            line.debit = ''
          } else {
            line.debit = line.net_amount || 0
            line.credit = ''
          }
          line.unitratio = line.foreign_unitratio || 0
          line.exratecode = line.foreign_exratecode || ''
          line.exratename = line.foreign_exratename || ''
          line.local_currency = line.local_exratecode || ''
          line.foreign_currency_type = line.foreign_type || ''
          if (line.sup) {
            line.supAccounts = line.sup.map(cell => {
              cell.uuid = cell.sup_id
              return cell
            })
            delete line.sup
          }
          return line
        })
      }
      this.setState({
        data: data,
        tbdata: fromJS(data).toJS(),
        status: 'change'
      })
    })
  }
  render() {
    const { type, status, book, loading, config, orgcode, typeOptions, charType, charInt, data, vouDate, username, remark, attachments, title, attachlist } = this.state
    const { type, status, loading, config, orgcode, typeOptions, tempTypes, charType, charInt, data, vouDate, username, remark, attachments, title, attachlist, tempTypeClass } = this.state
    return (
      <div className="menu-voucher-wrap" style={config.style}>
@@ -713,14 +1103,20 @@
          <Button className="add-background header-btn" disabled={status === 'empty'} onClick={() => this.triggersave('add')}>保存并新增</Button>
          <Button className="add-background header-btn" disabled={status === 'empty' || status === 'saved'} onClick={() => this.triggersave()}>保存</Button>
          <Button className="print-background header-btn" disabled={status !== 'saved'} onClick={this.triggerprint}>打印</Button>
          <Dropdown overlay={<div className="mk-voucher-dropdown-wrap">
            <SaveAsTemp tempTypes={tempTypes} onChange={this.triggerTempsave}/>
            <div className="split"></div>
            <LoadFromTemp tempTypes={tempTypes} onChange={this.triggerTempLoad}/>
          </div>} trigger={['click']}>
          <Button className="out-background header-btn" onClick={this.triggermore}>更多</Button>
          </Dropdown>
        </div> : null}
        {type === 'checkVoucher' ? <div className="voucher-header">
          <Button className="add-background header-btn" disabled={status === 'empty' || status === 'saved'} onClick={() => this.triggersave()}>保存</Button>
          <Button className="print-background header-btn" disabled={status !== 'saved'} onClick={this.triggerprint}>打印</Button>
          <Button className="out-background header-btn" onClick={this.triggerclose}>关闭</Button>
        </div> : null}
        <div className="voucher-body">
        <div className="voucher-body" style={{padding: `0px ${config.wrap.space || 0}px`}}>
          {type === 'createVoucher' || type === 'checkVoucher' ? <div className="pre-wrap">
            <div className="voucher-code">
              <Select value={charType} dropdownClassName="mk-vcode-dropdown" onChange={(val, option) => this.setState({charType: val, charName: option.props.charName, charInt: option.props.charint})}>
@@ -738,13 +1134,30 @@
            </div>
            <div className="voucher-affix">
              附单据 <InputNumber precision={0} value={attachments || 0} autoComplete="off" onChange={this.changeAttach}/> 张
              <ResetAttach config={config} book={book} orgcode={orgcode} attachlist={attachlist} onChange={(vals) => this.setState({attachlist: vals})}/>
              <ResetAttach config={config} orgcode={orgcode} voucherCode={this.state.voucherCode} attachlist={attachlist} onChange={this.resetAttachList}/>
              <ResetRemark remark={remark} ID={config.uuid + 'remark'} onChange={(val) => this.setState({remark: val})}/>
            </div>
          </div> : null}
          {type === 'createTemp' || type === 'checkTemp' ? <div className="pre-temp-wrap">
            <div className="temp-text">
              <span>模板名称:</span><Input value={title} placeholder="模板名称" autoComplete="off" onChange={(e) => this.setState({title: e.target.value})}/>
            </div>
            <div className="temp-text">
              <span>模板类型:</span>
              <Select value={tempTypeClass} dropdownClassName="mk-vcode-dropdown" onChange={(val, option) => this.setState({tempTypeClass: val, tempTypeName: option.props.children})}>
                {tempTypes.map(option =>
                  <Select.Option key={option.data_code} value={option.data_code}>{option.data_name}</Select.Option>
                )}
              </Select>
            </div>
            <div className="temp-action">
              <Button className="add-background header-btn" onClick={() => this.triggerTempsave()}>保存</Button>
              <Button className="out-background header-btn" onClick={this.triggerclose}>关闭</Button>
            </div>
          </div> : null}
          <VoucherTable config={config} loading={loading} data={data} onChange={this.dataChange}/>
        </div>
        <div className="user">制单人:{username}</div>
        {type === 'createVoucher' || type === 'checkVoucher' ? <div className="user">制单人:{username}</div> : null}
      </div>
    )
  }
src/tabviews/custom/components/module/voucher/index.scss
@@ -7,6 +7,7 @@
  background-size: cover;
  min-height: 150px;
  overflow-y: auto;
  overflow-x: hidden;
  color: #000000;
  .voucher-header {
@@ -20,7 +21,6 @@
    }
  }
  .voucher-body {
    padding: 0 30px;
    .voucher-code {
      display: inline-block;
      width: 160px;
@@ -71,6 +71,28 @@
        width: 60px;
      }
    }
    .pre-temp-wrap {
      padding: 10px 0px;
      .temp-text {
        display: inline-block;
        width: 22%;
        white-space: nowrap;
        padding-left: 10px;
        .ant-input {
          width: calc(100% - 70px);
        }
        .ant-select {
          width: calc(100% - 70px);
        }
      }
      .temp-action {
        float: right;
        .ant-btn {
          margin-left: 15px;
        }
      }
    }
  }
  .add-background {
@@ -107,3 +129,30 @@
    display: none;
  }
}
.mk-voucher-dropdown-wrap {
  background: #ffffff;
  border: 1px solid #d8d8d8;
  border-radius: 4px;
  min-height: 66px;
  .ant-btn {
    display: block;
    width: 100%;
    border: none;
  }
  .split {
    width: 100%;
    height: 1px;
    background: #d8d8d8;
  }
}
.mk-temp-add-modal {
  .ant-form-item {
    .ant-form-item-label {
      width: 170px;
    }
    .ant-form-item-control-wrapper {
      width: 250px;
      display: inline-block;
    }
  }
}
src/tabviews/custom/components/module/voucher/loadFromTemp/index.jsx
New file
@@ -0,0 +1,64 @@
import React, {Component} from 'react'
import { Button, Modal } from 'antd'
import './index.scss'
class LoadFromTemp extends Component {
  state = {
    visible: false,
    tempId: '',
  }
  submit = () => {
    const { name, typeChar, typeName } = this.state
    this.setState({visible: false})
    this.props.onChange(name, typeChar, typeName)
  }
  trigger = () => {
    this.setState({visible: true, tempId: ''})
  }
  render() {
    const { tempTypes } = this.props
    const { visible, tempId } = this.state
    return (
      <>
        <Button onClick={() => this.trigger()}>从模板中加载</Button>
        <Modal
          title="从模板中加载"
          wrapClassName="mk-temp-list-wrap"
          visible={visible}
          width={600}
          maskClosable={false}
          onOk={this.submit}
          onCancel={() => { this.setState({ visible: false })}}
          destroyOnClose
        >
          {visible ? <div className="document-wrap">
            <div className="document-title">
              <div className="folder-box">文件夹</div>
              <div className="folder">
                <span>文件</span>
              </div>
            </div>
            <div className="document-body">
              <div className="file-wrap">
                {tempTypes.map(doc => {
                  return <div className="file-item" key={doc.id}>
                    <span onClick={() => this.checkItem(doc.id)} className={'square-select' + (tempId === doc.id ? ' active' : '')}></span>
                    <span className="file-name">{doc.attachments_title}</span>
                  </div>
                })}
              </div>
            </div>
          </div> : null}
        </Modal>
      </>
    )
  }
}
export default LoadFromTemp
src/tabviews/custom/components/module/voucher/loadFromTemp/index.scss
New file
@@ -0,0 +1,148 @@
.mk-temp-list-wrap {
  .ant-modal-body {
    padding: 15px;
  }
  .document-wrap {
    .document-title {
      display: flex;
      background: #e8e8e8;
      line-height: 38px;
      border: 1px solid #d8d8d8;
      border-bottom: none;
      .folder-box {
        width: 200px;
        text-align: center;
        border-right: 1px solid #d8d8d8;
      }
      .folder {
        flex: 1;
        .square-select {
          top: 3px;
          margin: 0 10px;
        }
      }
    }
    .document-body {
      border: 1px solid #d8d8d8;
      height: 300px;
      display: flex;
      .doc-name {
        width: 200px;
        text-align: center;
        border-right: 1px solid #d8d8d8;
        height: 100%;
        overflow-y: auto;
        div {
          border-bottom: 1px solid #e8e8e8;
          height: 40px;
          line-height: 40px;
        }
        .active {
          background: var(--mk-sys-color1);
        }
      }
      .file-wrap {
        flex: 1;
        width: calc(100% - 200px);
        height: 100%;
        overflow-y: auto;
        .file-item {
          border-bottom: 1px solid #e8e8e8;
          height: 40px;
          line-height: 40px;
          .square-select {
            top: 4px;
            margin: 0 10px;
          }
          img {
            width: 20px;
            height: 20px;
            margin-top: -2px;
            margin-right: 5px;
          }
          .file-name {
            display: inline-block;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            vertical-align: top;
            width: calc(100% - 90px);
          }
        }
      }
    }
    .doc-name::-webkit-scrollbar, .file-wrap::-webkit-scrollbar {
      width: 7px;
    }
    .doc-name::-webkit-scrollbar-thumb, .file-wrap::-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);
    }
    .doc-name::-webkit-scrollbar-track, .file-wrap::-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);
    }
    .square-select {
      position: relative;
      display: inline-block;
      width: 16px;
      height: 16px;
      border: 1px solid #cccccc;
      box-sizing: content-box;
      margin: auto;
      margin-right: 5px;
      background-color: #ffffff;
      transition: border-color 0.2s;
      cursor: pointer;
    }
    .square-select.active {
      border-color: var(--mk-sys-color);
      background: var(--mk-sys-color);
    }
    .square-select.half {
      border-color: var(--mk-sys-color);
    }
    .square-select.disabled {
      border-color: #e8e8e8;
      background: #e8e8e8;
      cursor: default;
    }
    .square-select.disabled::before {
      border-color: #e8e8e8;
    }
    .square-select.half::before {
      display: none;
    }
    .square-select.half::after {
      position: absolute;
      top: 4px;
      left: 4px;
      content: ' ';
      display: block;
      width: 8px;
      height: 8px;
      background: var(--mk-sys-color);
    }
    .square-select::before {
      position: relative;
      top: 1px;
      left: 6px;
      content: ' ';
      display: block;
      width: 5px;
      height: 11px;
      border-style: solid;
      border-width: 0 2px 2px 0;
      border-color: #ffffff;
      transform: rotate(45deg);
    }
  }
}
src/tabviews/custom/components/module/voucher/resetAttach/addAttach/index.jsx
@@ -20,6 +20,7 @@
        files.forEach(item => {
          if (item.data_code === values.data_code) {
            values.data_name = item.data_name
            values.BID = item.id
          }
        })
@@ -67,8 +68,8 @@
                }
              ]
            })(<Select>
              {files.map((option, i) =>
                <Select.Option key={i} value={option.data_code}>{option.data_name}</Select.Option>
              {files.map(option =>
                <Select.Option key={option.id} value={option.data_code}>{option.data_name}</Select.Option>
              )}
            </Select>)}
          </Form.Item>
src/tabviews/custom/components/module/voucher/resetAttach/documents/index.jsx
@@ -2,54 +2,91 @@
class Documents extends Component {
  state = {
    folders: [],
    docs: [],
    selectKey: [],
    actFolder: ''
    actFolder: null
  }
  UNSAFE_componentWillMount() {
    const { documents } = this.props
    let folders = []
    let actFolder = documents[0].folder
    let docs = []
    documents.forEach(item => {
      folders.push(item.folder)
      if (item.folder === actFolder) {
        docs.push(item)
      }
    })
    let actFolder = documents[0] || null
    this.setState({selectKey: [], folders: Array.from(new Set(folders)), actFolder: actFolder, docs})
    this.setState({selectKey: [], actFolder: actFolder})
  }
  submit = () => {
    this.props.onChange()
    const { selectKey, actFolder } = this.state
    let items = []
    if (actFolder && selectKey.length > 0) {
      actFolder.attachments.forEach(doc => {
        if (selectKey.includes(doc.id)) {
          items.push(doc)
        }
      })
  }
  checkfolder = (val) => {
    this.props.onChange(items)
  }
  checkfolder = (id) => {
    const { documents } = this.props
    const { actFolder } = this.state
    if (actFolder === val) return
    if (!actFolder || actFolder.id === id) return
    let docs = []
    let _actFolder = null
    documents.forEach(item => {
      if (item.folder === val) {
        docs.push(item)
      if (item.id === id) {
        _actFolder = item
      }
    })
    this.setState({actFolder: val, selectKey: [], docs})
    this.setState({actFolder: _actFolder, selectKey: []}, () => {
      this.submit()
    })
  }
  checkItem = (id) => {
    const { selectKey } = this.state
    if (selectKey.includes(id)) {
      this.setState({selectKey: selectKey.filter(key => key !== id)}, () => {
        this.submit()
      })
    } else {
      this.setState({selectKey: [...selectKey, id]}, () => {
        this.submit()
      })
    }
  }
  checkAllItem = () => {
    const { selectKey, actFolder } = this.state
    if (!actFolder || actFolder.attachments.length === 0) return
    if (selectKey.length === actFolder.attachments.length) {
      this.setState({selectKey: []}, () => {
        this.submit()
      })
    } else {
      this.setState({selectKey: actFolder.attachments.map(item => item.id)}, () => {
        this.submit()
      })
    }
  }
  render() {
    const { folders, docs, selectKey, actFolder } = this.state
    const { documents } = this.props
    const { selectKey, actFolder } = this.state
    let checkAll = ''
    if (selectKey.length > 0) {
      checkAll = selectKey.length < docs.length ? ' half' : ' active'
    if (actFolder && selectKey.length > 0) {
      checkAll = selectKey.length < actFolder.attachments.length ? ' half' : ' active'
    } else if (!actFolder || actFolder.attachments.length === 0) {
      checkAll = ' disabled'
    }
    return (
@@ -57,18 +94,18 @@
        <div className="document-title">
          <div className="folder-box">文件夹</div>
          <div className="folder">
            <span className={'square-select' + checkAll}></span>
            <span onClick={this.checkAllItem} className={'square-select' + checkAll}></span>
            <span>文件</span>
          </div>
        </div>
        <div className="document-body">
          <div className="doc-name">
            {folders.map(folder => (<div className={actFolder === folder ? 'active' : ''} onClick={() => this.checkfolder(folder)} key={folder}>{folder}</div>))}
            {documents.map(folder => (<div className={actFolder.id === folder.id ? 'active' : ''} onClick={() => this.checkfolder(folder.id)} key={folder.id}>{folder.data_name}</div>))}
          </div>
          <div className="file-wrap">
            {docs.map(doc => {
            {actFolder && actFolder.attachments.map(doc => {
              return <div className="file-item" key={doc.id}>
                <span className={'square-select' + (selectKey.indexOf(doc.id) > -1 ? ' active' : '')}></span>
                <span onClick={() => this.checkItem(doc.id)} className={'square-select' + (selectKey.indexOf(doc.id) > -1 ? ' active' : '')}></span>
                <img src={doc.icon} alt=""/>
                <span className="file-name">{doc.attachments_title}</span>
              </div>
src/tabviews/custom/components/module/voucher/resetAttach/index.jsx
@@ -1,6 +1,6 @@
import React, {Component} from 'react'
import { fromJS } from 'immutable'
import { Button, Modal, notification } from 'antd'
import { Button, Modal, notification, Spin } from 'antd'
import moment from 'moment'
import { DeleteOutlined } from '@ant-design/icons'
// import md5 from 'md5'
@@ -23,15 +23,11 @@
    visible: false,
    upVisible: false,
    docVisible: false,
    files: [{data_code: 'ddd', data_name: '凭证'}],
    files: [],
    list: [],
    documents: [
      {id: '1223', folder: '凭证附件', icon: excelImg, attachments_title: '主表20230130173553.xlsx', attachments_url: 'http://主表20230130173553.xlsx'},
      {id: '1224', folder: '凭证附件', icon: excelImg, attachments_title: '主表2sdfsafjifjiji.xlsx', attachments_url: 'http://主表2sdfsafjifjiji.xlsx'},
      {id: '1225', folder: '凭证附件', icon: excelImg, attachments_title: '主表20230sjiejgiej.xlsx', attachments_url: 'http://主表20230sjiejgiej.xlsx'},
      {id: '1227', folder: '回执', icon: excelImg, attachments_title: '主表2023sdfrgtgfgd.xlsx', attachments_url: 'http://主表2023sdfrgtgfgd.xlsx'},
    ],
    selectDocs: []
    documents: [],
    selectDocs: [],
    loading: false
  }
  submit = () => {
@@ -40,23 +36,66 @@
  }
  trigger = () => {
    const { attachlist } = this.props
    let list = fromJS(attachlist).toJS()
    const { voucherCode, orgcode } = this.props
    let list = fromJS(this.props.attachlist).toJS()
    list = list.map(item => {
      item.icon = this.getIcon(item.attachments_url)
      return item
    })
    this.setState({visible: true, list: list})
    this.setState({visible: true, loading: true, list: list, files: [], documents: []})
    let param = {
      func: 's_get_fcc_voucher_attachments',
      voucher_code: voucherCode || '',
      orgcode: orgcode
    }
    Api.genericInterface(param).then(result => {
      this.setState({loading: false})
      if (!result.status) {
        notification.warning({
          top: 92,
          message: result.message,
          duration: 5
        })
        return
      }
      if (result.fcc_files) {
        let files = []
        let documents = []
        result.fcc_files.forEach(file => {
          files.push({data_code: file.data_code, data_name: file.data_name, id: file.id})
          file.attachments = file.attachments.map(item => {
            item.id = item.attach_id
            item.icon = this.getIcon(item.attachments_url)
            item.data_code = file.data_code
            item.data_name = file.data_name
            item.BID = file.id
            return item
          })
          documents.push(file)
        })
        this.setState({files, documents})
      }
    })
  }
  upSubmit = () => {
    const { config, book, orgcode } = this.props
    const { config, orgcode } = this.props
    if (!book) {
    if (!orgcode) {
      notification.warning({
        top: 92,
        message: '请选择账套!',
        message: '公司编码不可为空!',
        duration: 5
      })
      return
@@ -89,7 +128,7 @@
        typename: config.name,
        UserName: sessionStorage.getItem('User_Name') || '',
        FullName: sessionStorage.getItem('Full_Name') || '',
        BID: book.id
        BID: res.BID
      }
      Api.genericInterface(param).then(result => {
@@ -108,14 +147,15 @@
          data_code: res.data_code,
          data_name: res.data_name,
          attachments_title: res.attachments_title,
          attachments_url: res.url
          attachments_url: res.url,
          BID: res.BID
        }
        item.icon = this.getIcon(res.url)
        list.push(item)
        this.setState({list: list})
        this.setState({list: list, upVisible: false})
      })
    })
  }
@@ -160,11 +200,38 @@
  }
  docSubmit = () => {
    const { selectDocs, list } = this.state
    if (selectDocs.length > 0 && list.length > 0) {
      let _list = fromJS(list).toJS()
      let err = ''
      let ids = list.map(item => item.id)
      selectDocs.forEach(item => {
        if (!ids.includes(item.id)) {
          _list.push(item)
        } else {
          err += (err ? '、' : '') + item.attachments_title
        }
      })
      this.setState({list: _list, docVisible: false})
      if (err) {
        notification.warning({
          top: 92,
          message: '文件' + err + '已添加。',
          duration: 5
        })
      }
    } else {
      this.setState({list: [...list, ...selectDocs], docVisible: false})
    }
  }
  render() {
    const { visible, upVisible, docVisible, files, list, documents } = this.state
    const { visible, upVisible, docVisible, files, list, documents, loading } = this.state
    return (
      <>
@@ -180,8 +247,9 @@
          cancelText=""
          destroyOnClose
        >
          <Button type="link" className="attach-type-btn" onClick={() => this.setState({upVisible: true})}>上传新文件</Button>
          <Button type="link" className="attach-type-btn" onClick={() => this.setState({docVisible: true, selectDocs: []})}>从会计电子档案选择</Button>
          {loading ? <Spin /> : null}
          <Button type="link" className="attach-type-btn" disabled={loading} onClick={() => this.setState({upVisible: true})}>上传新文件</Button>
          <Button type="link" className="attach-type-btn" disabled={loading} onClick={() => this.setState({docVisible: true, selectDocs: []})}>从会计电子档案选择</Button>
          <div className="attach-selected-list">
            {list.map(item => {
              return <div className="attach-item" key={item.id}>
src/tabviews/custom/components/module/voucher/resetAttach/index.scss
@@ -1,6 +1,12 @@
.voucher-attach-wrap {
  .ant-modal-body {
    position: relative;
    padding: 15px;
    .ant-spin {
      position: absolute;
      top: 150px;
      left: 350px;
    }
    .attach-type-btn {
      border-width: 1px;
@@ -190,6 +196,14 @@
    .square-select.half {
      border-color: var(--mk-sys-color);
    }
    .square-select.disabled {
      border-color: #e8e8e8;
      background: #e8e8e8;
      cursor: default;
    }
    .square-select.disabled::before {
      border-color: #e8e8e8;
    }
    .square-select.half::before {
      display: none;
    }
src/tabviews/custom/components/module/voucher/saveAsTemp/index.jsx
New file
@@ -0,0 +1,122 @@
import React, {Component} from 'react'
import { Button, Modal, Form, Input, notification, Select, Divider } from 'antd'
import { PlusOutlined } from '@ant-design/icons'
import MKEmitter from '@/utils/events.js'
// import './index.scss'
const { Option } = Select
class SaveAsTemp extends Component {
  state = {
    visible: false,
    name: '',
    typeChar: '',
    typeName: '',
    menu: null
  }
  UNSAFE_componentWillMount() {
    let menuId = '16289973311406f3ko9nm8ehotdmu80o'
    let menu = window.GLOB.mkThdMenus.filter(m => m.MenuID === menuId)[0]
    if (menu) {
      let newtab = {
        ...menu,
        param: {}
      }
      this.setState({menu: newtab})
    }
  }
  submit = () => {
    const { name, typeChar, typeName } = this.state
    if (!typeChar) {
      notification.warning({
        top: 92,
        message: '请选择模板类型!',
        duration: 5
      })
      return
    } else if (!name) {
      notification.warning({
        top: 92,
        message: '请填写模板名称!',
        duration: 5
      })
      return
    }
    this.setState({visible: false})
    this.props.onChange(name, typeChar, typeName)
  }
  triggerSave = () => {
    this.setState({visible: true, name: '', typeChar: '', typeName: ''})
  }
  changeType = (val, option) => {
    if (option && option.props) {
      this.setState({typeChar: option.props.value, typeName: option.props.children})
    }
  }
  addType = () => {
    const { menu } = this.state
    this.setState({visible: false})
    MKEmitter.emit('modifyTabs', menu, true)
  }
  render() {
    const { tempTypes } = this.props
    const { visible, menu } = this.state
    return (
      <>
        <Button onClick={() => this.triggerSave()}>保存为模板</Button>
        <Modal
          title="添加模板"
          wrapClassName="mk-temp-add-modal"
          visible={visible}
          width={600}
          maskClosable={false}
          onOk={this.submit}
          onCancel={() => { this.setState({ visible: false })}}
          destroyOnClose
        >
          {visible ? <Form>
            <Form.Item label="模板类型">
              {menu ? <Select placeholder="请选择模板类型" onChange={this.changeType} dropdownRender={menus => (
                <div>
                  {menus}
                  <Divider style={{ margin: '4px 0' }} />
                  <div className="mk-add-book" onMouseDown={this.addType}>
                    <PlusOutlined /> 添加
                  </div>
                </div>
              )}>
                {tempTypes.map(item => (
                  <Option key={item.data_code} value={item.data_code}>{item.data_name}</Option>
                ))}
              </Select> : <Select placeholder="请选择模板类型" onChange={this.changeType}>
                {tempTypes.map(item => (
                  <Option key={item.data_code} value={item.data_code}>{item.data_name}</Option>
                ))}
              </Select>}
            </Form.Item>
            <Form.Item label="模板名称">
              <Input onChange={(e) => this.setState({name: e.target.value})}/>
            </Form.Item>
            <div style={{clear: 'both'}}></div>
          </Form> : null}
        </Modal>
      </>
    )
  }
}
export default SaveAsTemp
src/tabviews/custom/components/module/voucher/saveAsTemp/index.scss
src/tabviews/zshare/mutilform/index.jsx
@@ -41,6 +41,7 @@
  state = {
    formlist: [],    // 表单项
    ID: ''
  }
  record = {}
@@ -506,7 +507,7 @@
    this.record = record
    this.setState({ formlist }, () => {
    this.setState({ formlist, ID: this.props.data ? this.props.data.$$uuid || '' : '' }, () => {
      if (unload) return
      
      if (action.setting && action.setting.focus && fieldMap.has(action.setting.focus)) {
@@ -565,7 +566,8 @@
      obj_name: '',
      arr_field: '',
      table_type: 'Y',
      BID: BID || ''
      BID: BID || '',
      ID: this.state.ID || ''
    }
    if (param.LText) {
@@ -600,7 +602,8 @@
      obj_name: '',
      arr_field: '',
      table_type: 'Y',
      BID: BID || ''
      BID: BID || '',
      ID: this.state.ID || ''
    }
    if (mainparam.LText) {
@@ -661,7 +664,8 @@
        LText: _sql + form.base_sql,
        obj_name: form.field,
        arr_field: form.arr_field,
        BID: this.props.BID || ''
        BID: this.props.BID || '',
        ID: this.state.ID || ''
      }
      if (debug) {