king
2023-02-15 e69cc83c653ce78691aad2eedd4c71ca70f559c4
2023-02-15
5个文件已修改
2个文件已添加
653 ■■■■■ 已修改文件
package-lock.json 115 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
public/options.json 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/module/voucher/index.jsx 31 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/module/voucher/printVoucher/index.jsx 354 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/module/voucher/printVoucher/index.scss 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/module/voucher/voucherTable/index.jsx 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package-lock.json
@@ -3158,6 +3158,12 @@
      "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz",
      "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw=="
    },
    "@types/raf": {
      "version": "3.4.0",
      "resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.0.tgz",
      "integrity": "sha512-taW5/WYqo36N7V39oYyHP9Ipfd5pNFvGTIQsNGj86xV88YQ7GnI30/yMfKDF7Zgin0m3e+ikX88FvImnK4RjGw==",
      "optional": true
    },
    "@types/react": {
      "version": "16.9.2",
      "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.2.tgz",
@@ -5216,6 +5222,11 @@
        "node-int64": "^0.4.0"
      }
    },
    "btoa": {
      "version": "1.2.1",
      "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz",
      "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g=="
    },
    "buffer": {
      "version": "4.9.1",
      "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
@@ -5407,6 +5418,45 @@
      "version": "1.0.30001399",
      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001399.tgz",
      "integrity": "sha512-4vQ90tMKS+FkvuVWS5/QY1+d805ODxZiKFzsU8o/RsVJz49ZSRR8EjykLJbqhzdPgadbX6wB538wOzle3JniRA=="
    },
    "canvg": {
      "version": "3.0.10",
      "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.10.tgz",
      "integrity": "sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q==",
      "optional": true,
      "requires": {
        "@babel/runtime": "^7.12.5",
        "@types/raf": "^3.4.0",
        "core-js": "^3.8.3",
        "raf": "^3.4.1",
        "regenerator-runtime": "^0.13.7",
        "rgbcolor": "^1.0.1",
        "stackblur-canvas": "^2.0.0",
        "svg-pathdata": "^6.0.3"
      },
      "dependencies": {
        "@babel/runtime": {
          "version": "7.20.13",
          "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz",
          "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==",
          "optional": true,
          "requires": {
            "regenerator-runtime": "^0.13.11"
          }
        },
        "core-js": {
          "version": "3.28.0",
          "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.28.0.tgz",
          "integrity": "sha512-GiZn9D4Z/rSYvTeg1ljAIsEqFm0LaN9gVtwDCrKL80zHtS31p9BAjmTxVqTQDMpwlMolJZOFntUG2uwyj7DAqw==",
          "optional": true
        },
        "regenerator-runtime": {
          "version": "0.13.11",
          "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
          "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
          "optional": true
        }
      }
    },
    "capture-exit": {
      "version": "2.0.0",
@@ -7025,6 +7075,12 @@
      "requires": {
        "domelementtype": "1"
      }
    },
    "dompurify": {
      "version": "2.4.4",
      "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.4.tgz",
      "integrity": "sha512-1e2SpqHiRx4DPvmRuXU5J0di3iQACwJM+mFGE2HAkkK7Tbnfk9WcghcAmyWc9CRrjyRRUpmuhPUH6LphQQR3EQ==",
      "optional": true
    },
    "domutils": {
      "version": "1.7.0",
@@ -9504,6 +9560,11 @@
      "version": "4.2.1",
      "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz",
      "integrity": "sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q=="
    },
    "fflate": {
      "version": "0.4.8",
      "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz",
      "integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA=="
    },
    "figgy-pudding": {
      "version": "3.5.1",
@@ -12699,6 +12760,42 @@
      "version": "0.0.0",
      "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
      "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM="
    },
    "jspdf": {
      "version": "2.5.1",
      "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.5.1.tgz",
      "integrity": "sha512-hXObxz7ZqoyhxET78+XR34Xu2qFGrJJ2I2bE5w4SM8eFaFEkW2xcGRVUss360fYelwRSid/jT078kbNvmoW0QA==",
      "requires": {
        "@babel/runtime": "^7.14.0",
        "atob": "^2.1.2",
        "btoa": "^1.2.1",
        "canvg": "^3.0.6",
        "core-js": "^3.6.0",
        "dompurify": "^2.2.0",
        "fflate": "^0.4.8",
        "html2canvas": "^1.0.0-rc.5"
      },
      "dependencies": {
        "@babel/runtime": {
          "version": "7.20.13",
          "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz",
          "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==",
          "requires": {
            "regenerator-runtime": "^0.13.11"
          }
        },
        "core-js": {
          "version": "3.28.0",
          "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.28.0.tgz",
          "integrity": "sha512-GiZn9D4Z/rSYvTeg1ljAIsEqFm0LaN9gVtwDCrKL80zHtS31p9BAjmTxVqTQDMpwlMolJZOFntUG2uwyj7DAqw==",
          "optional": true
        },
        "regenerator-runtime": {
          "version": "0.13.11",
          "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
          "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
        }
      }
    },
    "jsprim": {
      "version": "1.4.1",
@@ -18887,6 +18984,12 @@
      "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz",
      "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM="
    },
    "rgbcolor": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz",
      "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==",
      "optional": true
    },
    "rimraf": {
      "version": "2.7.1",
      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
@@ -19982,6 +20085,12 @@
      "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz",
      "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA=="
    },
    "stackblur-canvas": {
      "version": "2.5.0",
      "resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.5.0.tgz",
      "integrity": "sha512-EeNzTVfj+1In7aSLPKDD03F/ly4RxEuF/EX0YcOG0cKoPXs+SLZxDawQbexQDBzwROs4VKLWTOaZQlZkGBFEIQ==",
      "optional": true
    },
    "stacktrace-parser": {
      "version": "0.1.10",
      "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz",
@@ -20260,6 +20369,12 @@
      "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.2.tgz",
      "integrity": "sha512-1gtApepKFweigFZj3sGO8KT8LvVZK8io146EzXrpVuWCDAbISz/yMucco3hWTkpZNoPabM+dnMOpy6Swue68Zg=="
    },
    "svg-pathdata": {
      "version": "6.0.3",
      "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
      "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==",
      "optional": true
    },
    "svgo": {
      "version": "1.3.0",
      "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.0.tgz",
package.json
@@ -61,6 +61,7 @@
    "jest-watch-typeahead": "0.3.1",
    "js-table2excel": "^1.0.3",
    "jsbarcode": "^3.11.3",
    "jspdf": "^2.5.1",
    "jssha": "^3.2.0",
    "jszip": "^3.10.0",
    "md5": "^2.2.1",
public/options.json
@@ -1,12 +1,12 @@
{
  "appId": "202108312122504607B107A83F55B40C98CCF",
  "appkey": "20210831212235413F287EC3BF489424496C8",
  "appId": "201912040924165801464FF1788654BC5AC73",
  "appkey": "20191106103859640976D6E924E464D029CF0",
  "mainSystemApi": "http://sso.mk9h.cn/cloud/webapi/dostars",
  "systemType": "",
  "externalDatabase": "",
  "lineColor": "",
  "filter": "false",
  "defaultApp": "mkindustry",
  "defaultApp": "mk",
  "defaultLang": "zh-CN",
  "WXAppID": "",
  "WXminiAppID": "",
@@ -17,6 +17,6 @@
  "transfer": "false",
  "keepPassword": "true",
  "platforms": ["H5", "wechat", "android", "ios", "wxMiniProgram"],
  "host": "http://demo.mk9h.cn",
  "service": "erp_new/"
  "host": "http://qingqiumarket.cn",
  "service": "MKWMS/"
}
src/tabviews/custom/components/module/voucher/index.jsx
@@ -12,8 +12,10 @@
import ResetRemark from './resetRemark'
import ResetAttach from './resetAttach'
import LoadFromTemp from './loadFromTemp'
import asyncComponent from '@/utils/asyncComponent'
import './index.scss'
const PrintVoucher = asyncComponent(() => import('./printVoucher'))
const { confirm } = Modal
class VoucherModule extends Component {
@@ -80,8 +82,8 @@
      }
    }
    // config.wrap.type = 'checkVoucher'
    // BID = '20230214130744811P0K95RQ155KG0QIQOFV'
    config.wrap.type = 'checkVoucher'
    BID = '20230214130744811P0K95RQ155KG0QIQOFV'
    // config.wrap.type = 'checkTemp'
    // BID = '20230214174458780MFR8IA576ON4VKNOLVH'
@@ -906,10 +908,6 @@
    })
  }
  triggerprint = () => {
  }
  dataChange = (data) => {
    this.setState({
      status: 'change',
@@ -926,12 +924,13 @@
      _val = parseInt(val)
    }
    
    this.setState({attachments: _val})
    this.setState({attachments: _val, status: 'change'})
  }
  changeVouDate = (val) => {
    const { type, status, saved } = this.state
    this.setState({vouDate: val})
    this.setState({vouDate: val, status: 'change'})
    if (type === 'createVoucher' && val && !saved && (status === 'empty' || status === 'change')) {
      this.updateVoucherChar(val)
@@ -1011,7 +1010,7 @@
      num = 0
    }
    this.setState({attachlist: vals, attachments: num})
    this.setState({status: 'change', attachlist: vals, attachments: num})
  }
  triggermore = () => {
@@ -1095,14 +1094,14 @@
  }
  render() {
    const { type, status, loading, config, orgcode, typeOptions, tempTypes, charType, charInt, data, vouDate, username, remark, attachments, title, attachlist, tempTypeClass } = this.state
    const { type, status, loading, config, orgcode, orgname, typeOptions, tempTypes, charType, charName, charInt, data, vouDate, username, remark, attachments, title, attachlist, tempTypeClass } = this.state
    return (
      <div className="menu-voucher-wrap" style={config.style}>
        {type === 'createVoucher' ? <div className="voucher-header">
          <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>
          <PrintVoucher ID={config.uuid + 'print'} data={data} orgname={orgname} vouDate={vouDate} charName={charName} charInt={charInt} attachments={attachments} disabled={status !== 'saved'}/>
          <Dropdown overlay={<div className="mk-voucher-dropdown-wrap">
            <SaveAsTemp tempTypes={tempTypes} onChange={this.triggerTempsave}/>
            <div className="split"></div>
@@ -1113,29 +1112,29 @@
        </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>
          <PrintVoucher ID={config.uuid + 'print'} data={data} orgname={orgname} vouDate={vouDate} charName={charName} charInt={charInt} attachments={attachments} disabled={status !== 'saved'}/>
          <Button className="out-background header-btn" onClick={this.triggerclose}>关闭</Button>
        </div> : null}
        <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})}>
              <Select value={charType} dropdownClassName="mk-vcode-dropdown" onChange={(val, option) => this.setState({status: 'change', charType: val, charName: option.props.charName, charInt: option.props.charint})}>
                {typeOptions.map(option =>
                  <Select.Option key={option.voucher_char_int} value={option.voucher_class} charName={option.voucher_char} charint={option.voucher_char_int}>{option.voucher_char}</Select.Option>
                )}
              </Select>
              <InputNumber precision={0} min={1} value={charInt} autoComplete="off" onChange={(val) => this.setState({charInt: val})}/> 号
              <InputNumber precision={0} min={1} value={charInt} autoComplete="off" onChange={(val) => this.setState({status: 'change', charInt: val})}/> 号
            </div>
            <div className="voucher-date">
              日期:<DatePicker value={vouDate} onChange={this.changeVouDate}/>
            </div>
            <div className="voucher-text">
              <Input value={title} placeholder="凭证文本" autoComplete="off" onChange={(e) => this.setState({title: e.target.value})}/>
              <Input value={title} placeholder="凭证文本" autoComplete="off" onChange={(e) => this.setState({status: 'change', title: e.target.value})}/>
            </div>
            <div className="voucher-affix">
              附单据 <InputNumber precision={0} value={attachments || 0} autoComplete="off" onChange={this.changeAttach}/> 张
              <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})}/>
              <ResetRemark remark={remark} ID={config.uuid + 'remark'} onChange={(val) => this.setState({status: 'change', remark: val})}/>
            </div>
          </div> : null}
          {type === 'createTemp' || type === 'checkTemp' ? <div className="pre-temp-wrap">
src/tabviews/custom/components/module/voucher/printVoucher/index.jsx
New file
@@ -0,0 +1,354 @@
import React, {Component} from 'react'
import { Button } from 'antd'
import moment from 'moment'
import html2Canvas from 'html2canvas'
import JsPDF from 'jspdf'
import './index.scss'
class printVoucher extends Component {
  state = {
    loading: false
  }
  trigger = () => {
    this.setState({loading: true})
    setTimeout(() => {
      this.getCanvas()
    }, 200)
  }
  getCanvas = () => {
    const { ID } = this.props
    let wrap = document.getElementById(ID)
    let elements = wrap.querySelectorAll('.mk-voucher-print-pdf-wrap')
    let  pageArr = []
    const opts = {
      scale: 1.5,        // 缩放比例,提高生成图片清晰度
      useCORS: false,    // 允许加载跨域的图片
      allowTaint: false, // 允许图片跨域,和 useCORS 二者不可共同使用
      tainttest: false,  // 检测每张图片已经加载完成
      logging: false     // 日志开关,发布的时候记得改成 false
    }
    elements = Array.from(elements)
    for (let index = 0; index < elements.length; index++) {
      // eslint-disable-next-line
      html2Canvas(elements[index], opts).then(canvas => {
        // a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
        const contentWidth = canvas.width
        const contentHeight = canvas.height
        const imgWidth = 595.28
        const imgHeight = (592.28 / contentWidth) * contentHeight
        const pageData = canvas.toDataURL('image/jpeg', 1.0)
        // 一页pdf显示html页面生成的canvas高度;
        const pageHeight = (contentWidth / 592.28) * 841.89
        // 未生成pdf的html页面高度
        const leftHeight = contentHeight
        pageArr.push({ pageData: pageData, pageHeight: pageHeight, leftHeight: leftHeight, imgWidth: imgWidth, imgHeight: imgHeight })
        if (pageArr.length === elements.length) {
          this.getPdf(pageArr)
        }
      })
    }
  }
  getPdf = (pageArr) => {
    const { orgname, vouDate, charName, charInt } = this.props
    let title = moment(vouDate).format('YYYY-MM-DD') + charName + '-' + charInt + orgname + moment().format('YYYYMMDDHHmmss')
    const PDF = new JsPDF('', 'pt', 'a4')
    pageArr.forEach((data, index) => {
      // 页面偏移
      let position = 0
      // 转换完毕,save保存名称后浏览器会自动下载
      // 当内容未超过pdf一页显示的范围,无需分页
      if (data.leftHeight < data.pageHeight) {
        // addImage(pageData, 'JPEG', 左,上,宽度,高度)设置
        PDF.addImage(data.pageData, 'JPEG', 0, 0, data.imgWidth, data.imgHeight)
      } else {
        // 超过一页时,分页打印(每页高度841.89)
        while (data.leftHeight > 0) {
          PDF.addImage(data.pageData, 'JPEG', 0, position, data.imgWidth, data.imgHeight)
          data.leftHeight -= data.pageHeight
          position -= 841.89
          if (data.leftHeight > 0) {
            PDF.addPage()
          }
        }
      }
      if (index + 1 === pageArr.length) {
        PDF.save(title + '.pdf')
        this.setState({loading: false})
      } else {
        // 未转换到最后一页时,pdf增加一页
        PDF.addPage()
      }
    })
  }
  getContent = () => {
    const { data, orgname, vouDate, charName, charInt, attachments } = this.props
    let list = []
    let items = []
    let index = 0
    data.forEach((cell, i) => {
      if (index < 10) {
        items.push(cell)
        index++
      } else {
        list.push([...items])
        index = 0
        items = []
      }
    })
    if (items.length > 0) {
      while (items.length < 5) {
        items.push({uuid: index + ''})
        index++
      }
      list.push(items)
    } else if (list.length === 0) {
      list = [[{uuid: '1'}, {uuid: '2'}, {uuid: '3'}, {uuid: '4'}, {uuid: '5'}]]
    }
    let total = this.getTotalLine(data)
    if (total.debit) {
      total.debit = total.debit.toFixed(2)
    }
    if (total.credit) {
      total.credit = total.credit.toFixed(2)
    }
    return <>
      {list.map((page, i) => (<div className="mk-voucher-print-pdf-wrap" key={i}>
        <div className="print-header">
          <div className="line">
            <div className="left"></div>
            <div className="center">记账凭证</div>
            <div className="right">附单据数:{attachments}</div>
          </div>
          <div className="line">
            <div className="left">单位:{orgname}</div>
            <div className="center">日期:{moment(vouDate).format('YYYY-MM-DD')}</div>
            <div className="right">凭证号:{charName}-{charInt}{list.length > 1 ? `(${i + 1}/${list.length})` : ''}</div>
          </div>
        </div>
        <div className="print-body">
          <div className="print-line" key="0">
            <div className="remark" style={{textAlign: 'center'}}>摘要</div>
            <div className="subject" style={{textAlign: 'center'}}>科目</div>
            <div className="credit" style={{textAlign: 'center'}}>借方金额</div>
            <div className="credit" style={{textAlign: 'center'}}>贷方金额</div>
          </div>
          {page.map(record => {
            let remark = record.subject_voucher_text || ''
            if (record.count_type === 'Y') {
              remark += `(数量:${record.fcc_count !== undefined ? record.fcc_count : ''},单价:${record.net_unitprice !== undefined ? record.net_unitprice : ''})`
            }
            if (record.foreign_currency_type === 'Y') {
              remark += `(货币:${record.exratename || ''},汇率:${record.unitratio !== undefined ? record.unitratio : ''},原币:${record.foreign_amount !== undefined ? record.foreign_amount : ''})`
            }
            let val = ''
            if (record.subject_code) {
              val = (record.subject_code || '') + ' ' + (record.subject_name || '')
              if (record.sup_accounting && record.supAccounts) {
                record.supAccounts.forEach(item => {
                  if (item.sup_acc_type === 'supplier') {
                    val += item.suppliername ? '_'  + item.suppliername : ''
                  } else if (item.sup_acc_type === 'customer') {
                    val += item.customername ? '_'  + item.customername : ''
                  } else if (item.sup_acc_type === 'department') {
                    val += item.co_pro_name ? '_' + item.co_pro_name : ''
                  } else if (item.sup_acc_type === 'project') {
                    val += item.projectname ? '_' + item.projectname : ''
                  } else if (item.sup_acc_type === 'inventory') {
                    val += item.productname ? '_' + item.productname : ''
                  } else if (item.sup_acc_type === 'employee') {
                    val += item.workername ? '_' + item.workername : ''
                  } else if (item.sup_acc_type === 'cash_flow') {
                    val += item.cash_flow_name ? '_' + item.cash_flow_name : ''
                  } else if (item.sup_acc_name) {
                    val += '_' + item.sup_acc_name
                  }
                })
              }
            }
            let debit = record.debit || record.debit === 0 ? record.debit : ''
            let credit = record.credit || record.credit === 0 ? record.credit : ''
            if (debit) {
              debit = debit.toFixed(2)
            }
            if (credit) {
              credit = credit.toFixed(2)
            }
            return <div className="print-line" key={record.uuid}>
              <div className="remark">{remark}</div>
              <div className="subject">{val}</div>
              <div className="credit">{debit}</div>
              <div className="credit">{credit}</div>
            </div>
          })}
          <div className="print-line" key="total">
            <div className="remark" style={{width: '60%'}}>合计:{total.subject_voucher_text}</div>
            <div className="credit">{total.debit}</div>
            <div className="credit">{total.credit}</div>
          </div>
        </div>
        <div className="print-footer">
          <div>主管:</div>
          <div>记账:</div>
          <div>审核:</div>
          <div>出纳:</div>
          <div>制单:</div>
        </div>
      </div>))}
    </>
  }
  getTotalLine = (data) => {
    let totalLine = {uuid: 'total', type: 'total'}
    let debit = ''
    let credit = ''
    data.forEach(item => {
      if (!isNaN(item.debit) && item.debit !== '') {
        if (debit === '') {
          debit = 0
        }
        debit += item.debit
      } else if (!isNaN(item.credit) && item.credit !== '') {
        if (debit === '') {
          debit = 0
        }
        if (credit === '') {
          credit = 0
        }
        credit += item.credit
      }
    })
    totalLine.debit = debit
    totalLine.credit = credit
    totalLine.subject_voucher_text = this.changeMoneyToChinese(debit)
    return totalLine
  }
  changeMoneyToChinese = (money) => {
    let cnNums = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']
    let cnIntRadice = ['', '拾', '佰', '仟']
    let cnIntUnits = ['', '万', '亿', '兆']
    let cnDecUnits = ['角', '分', '毫', '厘']
    let cnInteger = '整'
    let cnIntLast = '元'
    let maxNum = 999999999999999.9999 // 最大处理的数字
    let IntegerNum = null
    let DecimalNum = null
    let ChineseStr = ''
    let parts = null // 分离金额后用的数组,预定义
    let Symbol = ''  // 正负值标记
    if (money === '') return ''
    if (money >= maxNum) return '超出最大处理数字'
    if (money === 0) {
      ChineseStr = cnNums[0] + cnIntLast + cnInteger;
      return ChineseStr
    }
    if(money < 0) {
      money = -money
      Symbol = '负'
    }
    money = money.toString() // 转换为字符串
    if (money.indexOf('.') === -1) {
      IntegerNum = money
      DecimalNum = ''
    } else {
      parts = money.split('.')
      IntegerNum = parts[0]
      DecimalNum = parts[1].substr(0, 4)
    }
    if (parseInt(IntegerNum, 10) > 0) { // 获取整型部分转换
      let zeroCount = 0
      let IntLen = IntegerNum.length
      for (let i = 0; i < IntLen; i++) {
        let n = IntegerNum.substr(i, 1)
        let p = IntLen - i - 1
        let q = p / 4
        let m = p % 4
        if (n === '0') {
          zeroCount++
        } else {
          if (zeroCount > 0) {
            ChineseStr += cnNums[0]
          }
          zeroCount = 0 // 归零
          ChineseStr += cnNums[parseInt(n)] + cnIntRadice[m]
        }
        if (m === 0 && zeroCount < 4) {
          ChineseStr += cnIntUnits[q]
        }
      }
      ChineseStr += cnIntLast
    }
    if (DecimalNum !== '') { // 小数部分
      let decLen = DecimalNum.length
      for (let i = 0; i < decLen; i++) {
        let n = DecimalNum.substr(i, 1)
        if (n !== '0') {
          ChineseStr += cnNums[Number(n)] + cnDecUnits[i]
        }
      }
    }
    if (ChineseStr === '') {
      ChineseStr += cnNums[0] + cnIntLast + cnInteger
    } else if (DecimalNum === '') {
      ChineseStr += cnInteger
    }
    ChineseStr = Symbol + ChineseStr
    return ChineseStr
  }
  render() {
    const { disabled, ID } = this.props
    const { loading } = this.state
    return (
      <>
        <Button className="print-background header-btn" loading={loading} disabled={disabled} onClick={this.trigger}>打印</Button>
        {loading ? <div id={ID} className="mk-voucher-print-wrap">
          {this.getContent()}
        </div> : null}
      </>
    )
  }
}
export default printVoucher
src/tabviews/custom/components/module/voucher/printVoucher/index.scss
New file
@@ -0,0 +1,126 @@
.mk-voucher-print-wrap {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}
.mk-voucher-print-pdf-wrap {
  width: 1200px;
  padding: 80px;
  color: #000000;
  background: #ffffff;
  .print-header {
    .line {
      display: flex;
      margin-bottom: 10px;
      div {
        flex: 1;
        width: 33.33%;
        min-height: 5px;
      }
      .center {
        text-align: center;
      }
      .right {
        text-align: right;
      }
    }
    .line:first-child {
      .center {
        font-size: 24px;
      }
      .right {
        padding-top: 15px;
      }
    }
  }
  .print-footer {
    display: flex;
    div {
      flex: 1;
      width: 20%;
    }
  }
  .print-body {
    position: relative;
    border: 1px solid #000000;
    margin: 20px 0px;
    .print-line {
      position: relative;
      height: 60px;
      .remark {
        display: inline-block;
        width: 25%;
        padding: 0 3px;
      }
      .subject {
        display: inline-block;
        width: 35%;
        padding: 0 3px;
      }
      .credit {
        display: inline-block;
        width: 20%;
        line-height: 60px;
        text-align: right;
        padding: 0 3px;
      }
      .remark::after {
        content: '';
        position: absolute;
        width: 0px;
        height: 60px;
        left: 25%;
        top: 0;
        border-right: 1px solid #000000;
      }
    }
    .print-line:first-child {
      > div {
        text-align: center;
      }
    }
    .print-line:last-child {
      .remark {
        width: 60%;
      }
      .remark::after {
        display: none;
      }
    }
    .print-line:not(:last-child)::after {
      // border: 1px solid #000000;
      content: '';
      position: absolute;
      width: 100%;
      height: 0px;
      left: 0;
      bottom: 0;
      border-bottom: 1px solid #000000;
    }
  }
  .print-body::before {
    content: '';
    position: absolute;
    width: 0px;
    height: 100%;
    left: 60%;
    top: 0;
    border-right: 1px solid #000000;
  }
  .print-body:after {
    content: '';
    position: absolute;
    width: 0px;
    height: 100%;
    left: 80%;
    top: 0;
    border-right: 1px solid #000000;
  }
}
src/tabviews/custom/components/module/voucher/voucherTable/index.jsx
@@ -748,21 +748,21 @@
            if (record.sup_accounting && record.supAccounts) {
              record.supAccounts.forEach(item => {
                if (item.sup_acc_type === 'supplier') {
                  val += item.suppliercode ? '_' + item.suppliercode : ''
                  val += item.suppliercode ? '_' + item.suppliercode + ' ' + item.suppliername : ''
                } else if (item.sup_acc_type === 'customer') {
                  val += item.customercode ? '_' + item.customercode : ''
                  val += item.customercode ? '_' + item.customercode + ' ' + item.customername : ''
                } else if (item.sup_acc_type === 'department') {
                  val += item.co_pro_code ? '_' + item.co_pro_code : ''
                  val += item.co_pro_code ? '_' + item.co_pro_code + ' ' + item.co_pro_name : ''
                } else if (item.sup_acc_type === 'project') {
                  val += item.projectcode ? '_' + item.projectcode : ''
                  val += item.projectcode ? '_' + item.projectcode + ' ' + item.projectname : ''
                } else if (item.sup_acc_type === 'inventory') {
                  val += item.productcode ? '_' + item.productcode : ''
                  val += item.productcode ? '_' + item.productcode + ' ' + item.productname : ''
                } else if (item.sup_acc_type === 'employee') {
                  val += item.workercode ? '_' + item.workercode : ''
                  val += item.workercode ? '_' + item.workercode + ' ' + item.workername : ''
                } else if (item.sup_acc_type === 'cash_flow') {
                  val += item.cash_flow_code ? '_' + item.cash_flow_code : ''
                  val += item.cash_flow_code ? '_' + item.cash_flow_code + ' ' + item.cash_flow_name : ''
                } else if (item.sup_acc_code) {
                  val += '_' + item.sup_acc_code
                  val += '_' + item.sup_acc_code + ' ' + item.sup_acc_name
                }
              })
            }